黑马程序员:银行业务调度系统

------- android培训java培训、期待与您交流! ----------

银行业务调度系统 

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

Ø 银行内有6个业务窗口,1 - 4号窗口为普通窗口,5号窗口为快速窗口,6号窗口为VIP窗口。

Ø 有三种对应类型的客户:VIP客户,普通客户,快速客户(办理如交水电费、电话费之类业务的客户)。

Ø 异步随机生成各种类型的客户,生成各类型用户的概率比例为:

        VIP客户 :普通客户 :快速客户  =  1 3

Ø 客户办理业务所需时间有最大值和最小值,在该范围内随机设定每个VIP客户以及普通客户办理业务所需的时间,快速客户办理业务所需时间为最小值(提示:办理业务的过程可通过线程Sleep的方式模拟)。

Ø 各类型客户在其对应窗口按顺序依次办理业务。 

Ø 当VIP6号)窗口和快速业务(5号)窗口没有客户等待办理业务的时候,这两个窗口可以处理普通客户的业务,而一旦有对应的客户等待办理业务的时候,则优先处理对应客户的业务。

Ø 随机生成客户时间间隔以及业务办理时间最大值和最小值自定,可以设置。


系统分析:

 

系统设计:

NumberMachine 类

因为每个系统只有一个number machine,因此该类设置为单例模式:

	private NumberMachine(){}//构造函数私有化
	private static NumberMachine numberMachine = new NumberMachine();//静态对象 私有
	public static NumberMachine getInstance(){//静态方法返回自身对象
		return numberMachine;
	}
	

这个类用来管理NumberManager,因此应当有三个方法返回不同的NumberManager对象

	private NumberManager commonManager= new NumberManager();
	private NumberManager vipManager= new NumberManager();
	private NumberManager expressManager= new NumberManager();
	
	public NumberManager getCommonManager(){
		return commonManager;
	}
	
	public NumberManager getVipManager(){
		return vipManager;
	}
	
	public NumberManager getExpressManager(){
		return expressManager;
	}

NumberManager类, 用来管理相应类型的号码。

成员变量:

private int lastNumber =1;  //即将产生的下一个号码
private List<Integer> queueNumber=new ArrayList<Integer>();//每个manager单独维护自己的numberList,为面向接口编程,使用List<Integer> 来声明变量。

成员方法:

public synchronized int generateNewNumber();//产生号码,用户客户取号。
public synchronized int fetchNumber();//取一个号码,用于窗口获取任务。

因为二者分别处于不同线程并对同一个list进行添加和删除操作,因此要设为同步方法。


ServeiceWindow 类

设置三个类分别对应不同类型的窗口,CommonWindow, VIPWindow,ExpressWindow; VIPWindow和ExpressWindow都继承自 CommonWindow,


CommonWindow:

成员变量:

protected CustomerType type = CustomerType.COMMON;
protected int windowId = 1;
protected String windowName = "第"+windowId +"号"+type+"窗口";

构造方法:

public CommonWindow(CustomerType type,int id);

成员方法:

protected int fetchNumber() //获取一个现有客户,调用相应的NumberManager 的fetchNumber方法获取

protected int getServiceTime();// 这里给出一个最大值和最小值随机产生服务时间,

protected void resetType();//用于在每次循环时重置自己的客户类型,主要为其它两个类设计,因为他们的客户类型可能会有变化。

下面的start 方法是启动一个线程来循环获取任务:

public void start(){
	    ExecutorService pool = Executors.newSingleThreadExecutor();
	    pool.execute(new Runnable(){
	    	public void run(){
	    		while(true){
	    			System.out.println(windowName +"开始获取"+type+"任务");
	    			int number = CommonWindow.this.fetchNumber();
	    			if(number > 0){
	    				try {
	    					System.out.println(windowName+"正在为第"+number+"号"+type+"客户服务");
	    					Thread.sleep(CommonWindow.this.getServiceTime());
	    					} catch (InterruptedException e) {
	    						e.printStackTrace();
	    					}
	    				finally{
	    					resetType();
	    					}
	    				}
	    			else{
	    				//没有获取到客户, 空闲一秒
	    				System.out.println(windowName+"没有获取到"+type+"任务,空闲一秒");
	    				try {
	    					Thread.sleep(1000);
	    					} catch (InterruptedException e) {
	    						e.printStackTrace();
	    						}
	    				finally{
	    					resetType();
	    					}
	    				}
	    			}
	    		}
	    	});    
	    }

class VIPWindow extends CommonWindow

复写父类的fetchNumber方法:

先调用自己对应的NumberManager的fetchNumber 方法,如果返回值为0,改变type为Common,调用父类的fetchNumber方法来获取。


复写父类的resetType方法

将type重置为VIP

class ExpressWindow extends CommonWindow

复写父类的fetchNumber方法:
先调用自己对应的NumberManager的fetchNumber 方法,如果返回值为0,改变type为Common,调用父类的fetchNumber方法来获取。


复写父类的resetType方法

将type重置为Express

复写父类的getServiceTime,因为快速窗口的特点是服务速度快,服务时间使用最小时间。

MainClass

NumberMachine在类加载时加载,得到一个numbermachine和三个不同类型的number manager:

private static NumberMachine numberMachine  = NumberMachine.getInstance();
private static NumberManager commonNumberManager = numberMachine.getCommonManager();
private static NumberManager vipNumberManager = numberMachine.getVipManager();
private static NumberManager expressNumberManager = numberMachine.getExpressManager();

程序执行时:

1. new四个CommonWindow,一个VIPWindow,一个Expresswindow,并调用他们的start方法

2. 分别启动3个线程调用三个不同类型的NumberManager的generateNewNumber 来产生并记录新客户。

采用计时器的方式每隔一段时间调用一次,根据需求VIP,Common,Express客户的数量比例为1:6:3,时间间隔比为:6:1:2

部分代码如下:

		for(int i = 1; i<=4; i++){
			CommonWindow commonWindow = new CommonWindow(CustomerType.COMMON, i);
			commonWindow.start();
		}
		
		ScheduledExecutorService commonPool = Executors.newScheduledThreadPool(1);
		commonPool.scheduleAtFixedRate(
				new Runnable(){
					public void run(){
						int number = commonNumberManager.generateNewNumber();
						System.out.println("第"+number +"号普通客户等待服务.");
					}
				},
				Constants.COMMON_CUSTOMMER_SPAN,
				Constants.COMMON_CUSTOMMER_SPAN,
				TimeUnit.SECONDS);

其中Customertype使用枚举表示,而执行任务的最大最小时间、产生新客户的时间间隔均使用final常量来记录。


运行结果如下:

第1号普通窗口开始获取普通任务
第2号普通窗口开始获取普通任务
第3号普通窗口开始获取普通任务
第1号VIP窗口开始获取VIP任务
第1号VIP窗口没有获取到VIP任务
第4号普通窗口开始获取普通任务
第4号普通窗口没有获取到普通任务,空闲一秒
第1号普通窗口没有获取到普通任务,空闲一秒
第2号普通窗口没有获取到普通任务,空闲一秒
第1号快速窗口开始获取快速任务
第1号VIP窗口开始获取普通任务
第1号VIP窗口没有获取到普通任务,空闲一秒
第3号普通窗口没有获取到普通任务,空闲一秒
第1号快速窗口没有获取到快速任务
第1号快速窗口开始获取普通任务
第1号快速窗口没有获取到普通任务,空闲一秒
第2号普通窗口开始获取普通任务
第2号普通窗口没有获取到普通任务,空闲一秒
第4号普通窗口开始获取普通任务
第4号普通窗口没有获取到普通任务,空闲一秒
第1号普通窗口开始获取普通任务
第1号VIP窗口开始获取VIP任务
第1号普通窗口没有获取到普通任务,空闲一秒
第1号VIP窗口没有获取到VIP任务
第1号VIP窗口开始获取普通任务
第1号VIP窗口没有获取到普通任务,空闲一秒
第3号普通窗口开始获取普通任务
第3号普通窗口没有获取到普通任务,空闲一秒
第1号快速窗口开始获取快速任务
第1号快速窗口没有获取到快速任务
第1号快速窗口开始获取普通任务
第1号快速窗口没有获取到普通任务,空闲一秒
第1号普通客户等待服务.
第2号普通窗口开始获取普通任务
第2号普通窗口正在为第1号普通客户服务
第4号普通窗口开始获取普通任务

......

第17号快速客户等待服务
第35号普通客户等待服务.
第1号快速窗口开始获取快速任务
第1号快速窗口正在为第17号快速客户服务
第1号VIP窗口开始获取VIP任务
第1号VIP窗口没有获取到VIP任务
第1号VIP窗口开始获取普通任务
第1号VIP窗口正在为第26号普通客户服务

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值