首页 > Java > 面试题二 银行业务调度系统
2014
06-11

面试题二 银行业务调度系统

老规矩,先贴业务需求:

模拟实现银行业务调度系统逻辑,具体需求如下:

  • 银行内有6个业务窗口,1 – 4号窗口为普通窗口,5号窗口为快速窗口,6号窗口为VIP窗口。
  • 有三种对应类型的客户:VIP客户,普通客户,快速客户(办理如交水电费、电话费之类业务的客户)。
  • 异步随机生成各种类型的客户,生成各类型用户的概率比例为:
    VIP客户 :普通客户 :快速客户 = 1 :6 :3。
  • 客户办理业务所需时间有最大值和最小值,在该范围内随机设定每个VIP客户以及普通客户办理业务所需的时间,快速客户办理业务所需时间为最小值(提示:办理业务的过程可通过线程Sleep的方式模拟)。
  • 各类型客户在其对应窗口按顺序依次办理业务。
  • 当VIP(6号)窗口和快速业务(5号)窗口没有客户等待办理业务的时候,这两个窗口可以处理普通客户的业务,而一旦有对应的客户等待办理业务的时候,则优先处理对应客户的业务。
  • 随机生成客户时间间隔以及业务办理时间最大值和最小值自定,可以设置。
  • 不要求实现GUI,只考虑系统逻辑实现,可通过Log方式展现程序运行结果。

研读了该需求后,归纳该系统所实现的需求无非就是两个:窗口叫号、客户取号。这和日常生活中的银行日常业务也是一致的:银行开门 –> 窗口准备服务,叫号(不断循环) –> 来了一个客户,取号(循环) –> 不同窗口为自己的客户服务……

那如何去实现这个系统中的各个类呢?

首先,叫号、取号涉及到的数据都是号码,这时候应该想到用号码管理器(NumberManager)去管理这些号码(对外提供这两个方法)。由于有三类客户,每类客户的号码编排都是完全独立的,所以,我想到本系统一共要产生三个号码管理器对象,各自管理一类用户的排队号码。这三个号码管理器对象统一由一个号码机器(NumberMachine,取号机)进行管理,这个号码机器在整个系统中始终只能有一个,所以,它要被设计成单例。

各类型客户在其对应窗口按顺序依次办理业务 ,准确地说,应该是窗口依次叫号,此时,应定义一个服务窗口类(ServiceWindow),这几个类的设计如下:

a bank system

① NumberManager类

/**
 * 号码管理器:NumberManager,主要有:
 * 两个字段:lastNumber:存储上一个客户号码,queueNumber:存储所有等待服务的客户号码的队列集合
 * 两种方法:客户取号、窗口叫号
 * @author flyne.org
 */
public class NumberManager {
	private static int lastNumber = 1;
	private static List<Integer> queueNumber = new ArrayList<>();

	//下面两个方法要考虑同步(不同线程调用)

	//取号:客户来了取号调用此方法
	public synchronized static Integer generateNewNumber(){
		queueNumber.add(lastNumber);
		return lastNumber++;
	}

	//叫号:窗口服务调用此方法
	public synchronized static Integer fetchServiceNumber(){
		if(queueNumber.size() > 0){
			return queueNumber.remove(0);
		}else{
			return null;
		}

	}
}

② NumberMachine类

/**
 * 取号机:NumberMachine,注意事项:
 * ① 定义三个成员变量分别指向三个NumberManager对象,分别表示普通、快速和VIP客户的号码管理器
 * ② 将NumberMachine类设计成单例。
 * @author flyne.org
 *
 */
public class NumberMachine {
	private NumberManager commonManager = new NumberManager();
	private NumberManager expressManager = new NumberManager();
	private NumberManager vipManager = new NumberManager();
	public NumberManager getCommonManager() {
		return commonManager;
	}
	public NumberManager getExpressManager() {
		return expressManager;
	}
	public NumberManager getVipManager() {
		return vipManager;
	}

	//单例
	private static NumberMachine instance = new NumberMachine();
	private NumberMachine(){}
	public static NumberMachine getInstance(){
		return instance;
	}
}

③ ServiceWindow类

/**
 * 服务窗口类:ServiceWindow
 * 定义三个方法分别对三种客户进行服务
 * @author flyne.org
 */
public class ServiceWindow {
	//窗口类型(同客户类型),默认是普通窗口(因为普通窗口最多)
	private CustomerType type = CustomerType.COMMON;
	//窗口id,默认值为1
	private int windowId = 1;

	public void setType(CustomerType type) {
		this.type = type;
	}

	public void setWindowId(int windowId) {
		this.windowId = windowId;
	}

	//叫号:根据服务窗口的类别分别循环调用三个不同的方法。
	public void start(){
		Executors.newSingleThreadExecutor().execute(new Runnable(){
			public void run() {
				while(true){
					switch(type){
						case COMMON:
							commonService();
							break;
						case EXPRESS:
							expressService();
							break;
						case VIP:
							vipService();
							break;
					}
				}
			}
		});
	}

	private void commonService() {
		String windowName = "第" + windowId + "号" + type + "窗口";
		Integer number = NumberMachine.getInstance().getCommonManager().fetchServiceNumber();
		System.out.println(windowName + "正在获取任务");
		if(number != null){
			System.out.println(windowName + "正在为" + number + "号普通客户服务");
			long beginTime = System.currentTimeMillis();
			//服务时间(随机值,1000~10000)
			long serveTime = new Random().nextInt(Constants.MAX_SERVICE_TIME - Constants.MIN_SERVICE_TIME) + Constants.MIN_SERVICE_TIME;
			try {
				Thread.sleep(serveTime);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			long durationTime = System.currentTimeMillis() - beginTime;
			System.out.println(windowName + "为第" + number + "个普通客户完成服务,耗时" + durationTime);
		}else{
			System.out.println(windowName + "没有取到服务任务,先休息一秒钟");
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	private void expressService() {
		String windowName = "第" + windowId + "号" + type + "窗口";
		Integer number = NumberMachine.getInstance().getExpressManager().fetchServiceNumber();
		System.out.println(windowName + "正在获取任务");
		if(number != null){
			long beginTime = System.currentTimeMillis();
			//服务时间(快速客户为最小值)
			long serveTime = Constants.MIN_SERVICE_TIME;
			try {
				Thread.sleep(serveTime);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			long durationTime = System.currentTimeMillis() - beginTime;
			System.out.println(windowName + "为第" + number + "个快速客户完成服务,耗时" + durationTime);
		}else{
			System.out.println(windowName + "没有取到服务任务,准备为普通客户服务");
			commonService();
		}
	}

	private void vipService() {
		String windowName = "第" + windowId + "号" + type + "窗口";
		Integer number = NumberMachine.getInstance().getVipManager().fetchServiceNumber();
		System.out.println(windowName + "正在获取任务");
		if(number != null){
			long beginTime = System.currentTimeMillis();
			//服务时间(随机值,1000~10000)
			long serveTime = new Random().nextInt(Constants.MAX_SERVICE_TIME - Constants.MIN_SERVICE_TIME) + Constants.MIN_SERVICE_TIME;
			try {
				Thread.sleep(serveTime);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			long durationTime = System.currentTimeMillis() - beginTime;
			System.out.println(windowName + "为第" + number + "个VIP客户完成服务,耗时" + durationTime);
		}else{
			System.out.println(windowName + "没有取到服务任务,准备为普通客户服务");
			commonService();
		}
	}
}

④ CustomerType类和Constants类

在ServiceWindow类中使用了CustomerType表示用户类型(窗口类型),还使用了一些常量,这些常量定义在Constants类中。

/**
 * 客户类型:CustomerType,也可用来表示窗口类型。
 * 系统中有三种类型的客户,所以用定义一个枚举类。
 * @author flyne.org
 */
public enum CustomerType {
	COMMON,EXPRESS,VIP;

	public String toString(){
		switch(this){
			case COMMON:
				return "普通";
			case EXPRESS:
				return "快速";
			case VIP:
				return name();
		}
		return null;
	}
}
-------------------------割-----------------------------
public class Constants {
	//服务时间(分最小和最大)
	public static int MAX_SERVICE_TIME = 10000;
	public static int MIN_SERVICE_TIME = 1000;

	//普通客户间隔时间(1秒钟来一个)
	public static int COMMON_CUSTOMER_INTERVAL_TIME = 1;
}

⑤ 测试类:MainClass类

public class MainClass {
	public static void main(String[] args) {
		//启动几个窗口(4个普通窗口、1个快速窗口和1个vip窗口),并开始叫号
		for(int i = 1 ;i < 5;i++){
			ServiceWindow commonWindow = new ServiceWindow();
			commonWindow.setWindowId(i);
			commonWindow.start();
		}

		ServiceWindow expressWindow = new ServiceWindow();
		expressWindow.setType(CustomerType.EXPRESS);
		expressWindow.start();

		ServiceWindow vipWindow = new ServiceWindow();
		vipWindow.setType(CustomerType.EXPRESS);
		vipWindow.start();

		//下面三个定时器模拟三类客户不停地取号
		//定时去创建新的普通客户号码
		Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
				new Runnable(){
					public void run() {
						Integer number = NumberMachine.getInstance().getCommonManager().generateNewNumber();
						System.out.println(number + "号普通客户等待服务");
					}
				},
				0,
				Constants.COMMON_CUSTOMER_INTERVAL_TIME, //每隔1秒钟来一个普通客户
				TimeUnit.SECONDS
			);

		//定时去创建新的快速客户号码
		Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
				new Runnable(){
					public void run() {
						Integer number = NumberMachine.getInstance().getExpressManager().generateNewNumber();
						System.out.println(number + "号快速客户等待服务");
					}
				},
				0,
				Constants.COMMON_CUSTOMER_INTERVAL_TIME * 2, //每隔2秒钟来一个快速客户
				TimeUnit.SECONDS
			);

		//定时去创建新的vip客户号码
		Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
				new Runnable(){
					public void run() {
						Integer number = NumberMachine.getInstance().getVipManager().generateNewNumber();
						System.out.println(number + "号vip客户等待服务");
					}
				},
				0,
				Constants.COMMON_CUSTOMER_INTERVAL_TIME * 6, //每隔6秒钟来一个vip客户
				TimeUnit.SECONDS
			);

	}
}

运行上面的测试类,控制台输出如下结果:

第1号快速窗口正在获取任务
第1号快速窗口正在获取任务
第1号快速窗口没有取到服务任务,准备为普通客户服务
第1号快速窗口正在获取任务
第1号快速窗口没有取到服务任务,先休息一秒钟
第2号普通窗口正在获取任务
第2号普通窗口没有取到服务任务,先休息一秒钟
第4号普通窗口正在获取任务
第4号普通窗口没有取到服务任务,先休息一秒钟
第3号普通窗口正在获取任务
第1号普通窗口正在获取任务
第3号普通窗口没有取到服务任务,先休息一秒钟
第1号快速窗口没有取到服务任务,准备为普通客户服务
第1号普通窗口没有取到服务任务,先休息一秒钟
第1号快速窗口正在获取任务
第1号快速窗口没有取到服务任务,先休息一秒钟
1号普通客户等待服务
2号快速客户等待服务
3号vip客户等待服务
第1号快速窗口正在获取任务
第2号普通窗口正在获取任务
第2号普通窗口正在为2号普通客户服务
第4号普通窗口正在获取任务
第1号普通窗口正在获取任务
第1号普通窗口没有取到服务任务,先休息一秒钟
第3号普通窗口正在获取任务
第3号普通窗口没有取到服务任务,先休息一秒钟
第4号普通窗口正在为3号普通客户服务
第1号快速窗口正在获取任务
4号普通客户等待服务
…………

通过这两个系统的设计,对面向对象设计思想的认识更加的深刻,在以后的学习中,一定要更加注意面向对象思维的培养!


留下一个回复

你的email不会被公开。