黑马程序员-------(面试题)银行业务调度系统

-------------java培训android培训、java博客、java学习型技术博客、期待与您交流! --------------

银行业务调度系统的项目需求


面向对象的分析与设计

有三种对应类型的客户:VIP客户,普通客户,快速客户 ,异步随机生成各种类型的客户,各类型客户在其对应窗口按顺序依次办理业务 。
首先,经常在银行办理业务的人更有利于理解本系统,例如,我经常陪老婆跑银行,对银行的这个业务算是比较熟悉了,我知道每一个客户其实就是由银行的一个取号机器产生号码的方式来表示的。所以,我想到要有一个号码管理器对象,让这个对象不断地产生号码,就等于随机生成了客户。
由于有三类客户,每类客户的号码编排都是完全独立的,所以,我想到本系统一共要产生三个号码管理器对象,各自管理一类用户的排队号码。这三个号码管理器对象统一由一个号码机器进行管理,这个号码机器在整个系统中始终只能有一个,所以,它要被设计成单例。
各类型客户在其对应窗口按顺序依次办理业务 ,准确地说,应该是窗口依次叫号。
各个窗口怎么知道该叫哪一个号了呢?它一定是问的相应的号码管理器,即服务窗口每次找号码管理器获取当前要被服务的号码。
如果我不是多次亲身经历银行的这种业务,再加之积累了大量面向对象的应用开发经验,我也不知道能否轻松进行这种设计,能否发掘出其中隐含的对象信息,我真说不出具体的经验是什么,就是日积月累出来的一种感觉。难道这就是传说中的:“只可意会,不可言传?”

类图

画图非常有助于理解和分析问题,


NumberManager和NumberMachine类

NumberManager类
定义一个用于存储上一个客户号码的成员变量和用于存储所有等待服务的客户号码的队列集合。
定义一个产生新号码的方法和获取马上要为之服务的号码的方法,这两个方法被不同的线程操作了相同的数据,所以,要进行同步。

package com.isoftstone.interview.bank;

import java.util.ArrayList;
import java.util.List;

public class NumberManager {
	private int lastNumber =1 ;
	private List<Integer> queueNumber = new ArrayList<Integer>();
	//两个独立的线程【generateNewManager、fetchServiceNumber】调用共同的数据,可能出现线程安全,所以加同步
	public synchronized Integer generateNewManager(){
		//队列添加排列服务号码
		queueNumber.add(lastNumber);
		return lastNumber++;
	}
	//两个独立的线程【generateNewManager、fetchServiceNumber】调用共同的数据,可能出现线程安全,所以加同步
	//因为可能返回null值,所以用自动拆装箱Integer类型
	public synchronized Integer fetchServiceNumber(){
		Integer number = null;
		if(queueNumber.size()>0){
			//队列,取出头一个
			return queueNumber.remove(0);
		}
		return number;
	}
	
	
	
	
	
}


NumberMachine类
定义三个成员变量分别指向三个NumberManager对象,分别表示普通、快速和VIP客户的号码管理器,定义三个对应的方法来返回这三个NumberManager对象。
将NumberMachine类设计成单例。
package com.isoftstone.interview.bank;


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 NumberMachine(){}
	//内部创建一个实例对象
	private static NumberMachine instance = new NumberMachine();
	//静态方法,获取对象
	public static NumberMachine getInstance(){
		return instance;
	}
	
	
}
ServiceWindow与CustomerType枚举类
CustomerType枚举类

系统中有三种类型的客户,所以用定义一个枚举类,其中定义三个成员分别表示三种类型的客户。
重写toString方法,返回类型的中文名称。这是在后面编码时重构出来的,刚开始不用考虑。

package com.isoftstone.interview.bank;

public enum CustomerType {
	COMMON,EXPRESS,VIP;
	//type的返回值就是toString()的方法
	public String toString(){
		switch(this){
		case COMMON:
			return "普通";
		case EXPRESS:
			return "快速";
		case VIP:
			return name();		
		}
		return null;
	}
}


ServiceWindow类
定义一个start方法,内部启动一个线程,根据服务窗口的类别分别循环调用三个不同的方法。 
定义三个方法分别对三种客户进行服务,为了观察运行效果,应详细打印出其中的细节信息。
package com.isoftstone.interview.bank;

import java.util.Random;
import java.util.concurrent.Executors;

public class ServiceWindow {
	//默认窗口的类型是common
	private CustomerType type=CustomerType.COMMON;
	public void setType(CustomerType type) {
		this.type = type;
	}
	public void setWindowId(int windowId) {
		this.windowId = windowId;
	}
	private int windowId = 1;
	public void start(){
		//JDK1.5的线程【性能较优】
		//创建一个线程池,把任务交给线程池之后,线程池再让空闲的线程执行。
		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();
			int maxRand = Constants.MAX_SERVICE_TIME-Constants.MIN_SERVICE_TIME;	//9000
			//0~8999 1~9000 1001~10000
			long serverTime = new Random().nextInt(maxRand)+1+Constants.MIN_SERVICE_TIME;	
			try {
				Thread.sleep(serverTime);
			} catch (InterruptedException e) {e.printStackTrace();}
			long endTime = System.currentTimeMillis();
			long costTime = endTime-beginTime;
			System.out.println(windowName+"为第"+number+"个"+type+"客户完成服务,耗时"+costTime/1000+"秒。");
		}else{
			System.out.println(windowName+"没有取到任务,先休息1秒");
			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){
			System.out.println(windowName+"为第"+number+"个"+type+"客户服务");
			long beginTime = System.currentTimeMillis();
			//int maxRand = Constants.MAX_SERVICE_TIME-Constants.MIN_SERVICE_TIME;	//9000
			//0~8999 1~9000 1001~10000
			//long serverTime = new Random().nextInt(maxRand)+1+Constants.MIN_SERVICE_TIME;	
			try {
				//快速服务时间,只能是最小值
				Thread.sleep(Constants.MIN_SERVICE_TIME);
			} catch (InterruptedException e) {e.printStackTrace();}
			long endTime = System.currentTimeMillis();
			long costTime = endTime-beginTime;
			System.out.println(windowName+"为第"+number+"个"+type+"客户完成服务,耗时"+costTime/1000+"秒。");
		}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){
			System.out.println(windowName+"为第"+number+"个"+type+"客户服务");
			long beginTime = System.currentTimeMillis();
			int maxRand = Constants.MAX_SERVICE_TIME-Constants.MIN_SERVICE_TIME;	//9000
			//0~8999 1~9000 1001~10000
			long serverTime = new Random().nextInt(maxRand)+1+Constants.MIN_SERVICE_TIME;	
			try {
				Thread.sleep(serverTime);
			} catch (InterruptedException e) {e.printStackTrace();}
			long endTime = System.currentTimeMillis();
			long costTime = endTime-beginTime;
			System.out.println(windowName+"为第"+number+"个"+type+"客户完成服务,耗时"+costTime/1000+"秒。");
		}else{
			//对于不是快速服务的窗口,当没有取到任务时,就不是休息了
			System.out.println(windowName+"没有取到任务!");
			//而是去调用commonService()
			commonService();
		}
	}
}

MainClass类与Constants类

Constants类

定义三个常量:MAX_SERVICE_TIME、MIN_SERVICE_TIME、COMMON_CUSTOMER_INTERVAL_TIME

package com.isoftstone.interview.bank;
//定义一个常量类
public class Constants {
	//最大10秒
	public static int MAX_SERVICE_TIME=10000;
	//最新1秒
	public static int MIN_SERVICE_TIME=1000;
	//定义普通客户数量 
	public static int COMMON_CUSTOMER_INTERVAL_TIME=1;
}


MainClass类
用for循环创建出4个普通窗口,再创建出1个快速窗口和一个VIP窗口。
接着再创建三个定时器,分别定时去创建新的普通客户号码、新的快速客户号码、新的VIP客户号码。

package com.isoftstone.interview.bank;

import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class MainClass {

	public static void main(String[] args) {
		
		for(int i =1; i<5;i++){
			ServiceWindow commonWindow = new ServiceWindow();
			commonWindow.setWindowId(i);
			//启动对于类型的窗口【switch(type)】
			commonWindow.start();
		}
		
		ServiceWindow expressWindow = new ServiceWindow();
		expressWindow.setType(CustomerType.EXPRESS);
		//启动对于类型的窗口【switch(type)】
		expressWindow.start();
		
		ServiceWindow vipWindow = new ServiceWindow();
		vipWindow.setType(CustomerType.VIP);
		//启动对于类型的窗口【switch(type)】
		vipWindow.start();
		
		//创建一个【调度线程池】,不是过多长时间运行,而是连续的运行
		//普通客户
		Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
				new Runnable(){
					public void run() {
						Integer number = NumberMachine.getInstance().getCommonManager().generateNewManager();
						System.out.println(number+"号普通客户等待服务");
					}}, 
				0, 
				Constants.COMMON_CUSTOMER_INTERVAL_TIME, 
				TimeUnit.SECONDS);
		
		//快速客户
		Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
				new Runnable(){
					public void run() {
						Integer number = NumberMachine.getInstance().getExpressManager().generateNewManager();
						System.out.println(number+"号快速客户等待服务");
						
					}}, 
				0, 
				Constants.COMMON_CUSTOMER_INTERVAL_TIME*3, 
				TimeUnit.SECONDS);
		//VIP客户
		Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
				new Runnable(){
					public void run() {
						Integer number = NumberMachine.getInstance().getVipManager().generateNewManager();
						System.out.println(number+"号VIP客户等待服务");
						
					}}, 
				0, 
				Constants.COMMON_CUSTOMER_INTERVAL_TIME*6, 
				TimeUnit.SECONDS);	
	}
}
运行结果

第2号普通窗口没有取到任务,先休息1秒
第1号快速窗口为第1个快速客户完成服务,耗时1秒。
第1号快速窗口正在获取任务
第1号快速窗口没有取到任务
第1号快速窗口正在获取任务
第1号快速窗口没有取到任务,先休息1秒
3号普通客户等待服务
第3号普通窗口正在获取任务
第3号普通窗口为第3个普通客户服务
第1号快速窗口正在获取任务
第1号快速窗口没有取到任务
第1号快速窗口正在获取任务
第1号快速窗口没有取到任务,先休息1秒
第2号普通窗口正在获取任务
第2号普通窗口没有取到任务,先休息1秒
4号普通客户等待服务
2号快速客户等待服务
第1号快速窗口正在获取任务
第2号普通窗口正在获取任务
第2号普通窗口为第4个普通客户服务
第1号快速窗口为第2个快速客户服务
5号普通客户等待服务
第4号普通窗口为第1个普通客户完成服务,耗时3秒。
第4号普通窗口正在获取任务
第4号普通窗口为第5个普通客户服务
第1号快速窗口为第2个快速客户完成服务,耗时1秒。
第1号快速窗口正在获取任务
第1号快速窗口没有取到任务
第1号快速窗口正在获取任务
第1号快速窗口没有取到任务,先休息1秒
6号普通客户等待服务
第2号普通窗口为第4个普通客户完成服务,耗时1秒。
第2号普通窗口正在获取任务
第2号普通窗口为第6个普通客户服务
第1号快速窗口正在获取任务
第1号快速窗口没有取到任务
第1号快速窗口正在获取任务
第1号快速窗口没有取到任务,先休息1秒
7号普通客户等待服务
3号快速客户等待服务
2号VIP客户等待服务
第1号VIP窗口为第1个VIP客户完成服务,耗时5秒。
第1号VIP窗口正在获取任务
第1号VIP窗口为第2个VIP客户服务
第3号普通窗口为第3个普通客户完成服务,耗时3秒。
第3号普通窗口正在获取任务
第3号普通窗口为第7个普通客户服务
第1号快速窗口正在获取任务
第1号快速窗口为第3个快速客户服务
8号普通客户等待服务
第1号快速窗口为第3个快速客户完成服务,耗时1秒。
第1号快速窗口正在获取任务
第1号快速窗口没有取到任务
第1号快速窗口正在获取任务
第1号快速窗口为第8个普通客户服务
9号普通客户等待服务
第1号普通窗口为第2个普通客户完成服务,耗时6秒。
第1号普通窗口正在获取任务
第1号普通窗口为第9个普通客户服务
10号普通客户等待服务
4号快速客户等待服务


-------------java培训android培训、java博客、java学习型技术博客、期待与您交流! --------------

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值