黑马程序员:感悟“银行业务调度系统”
2012-05-11 09:27
281 查看
---------------------- android培训、java培训、期待与您交流! -----------------------
需求分析:
*银行有6个业务窗口,1-4号窗口是普通窗口,5号窗口为快速窗口,6号窗口是VIP窗口
*有三种对应类型的客户:VIP客户、普通客户、快速客户(办理如交水电费、电话费之类业务的客户)
*异步随机生成各种类型的客户,生成各类型客户概率比例:VIP客户:普通客户:快速客户=1:6:3
*客户办理业务所需时间有最大、最小值,在该范围内随机设定每个VIP客户及普通客户办理业务所需要的时间, 快速客户办理业务所需时间为最小值(办理业务的过 程可通过sleep())模拟
*各类型客户在其对应窗口依次办理业务(由窗口叫号)
*当VIP(6号)窗口和快速窗口没有客户等待办理业务时,可以办理普通客户业务。而一旦有普通客户等待办理业务, 优先处理对应客户的业务
*随机生成客户时间间隔及业务办理时间最大值、最小值
*不必实现GUI,只实现业务逻辑,可通过LOG方式展现程序运行结果
面向对象的分析设计
*有三种对应类型的客户:VIP客户、普通客户、快速客户(办理如交水电费、电话费之类业务的客户)
每个客户的表示方法:取号机产生一个号码。所以要有号码管理器对象(不断产生随机号码)
三类客户的号码编排是完全独立的,所以要有3个号码管理器对象,各自管理一类客户的排除号码
这3个号码管理器对象统一由一个号码机器管理(在号码机器选择要办理哪种客户类型的业务),这个号码机器在系统中始终只能有一个,设计成单例
*各类型客户在其对应窗口依次办理业务(窗口依次叫号)
窗口怎么知道叫哪个号码?它应该询问号码管理器。即:服务窗口每次找号码管理器获取当前要被服务的号码
画类图,使思路清晰:
2. 类的实现
*NumberManager类:
成员变量:存储上一个客户号码
等待服务的客户号码的队列集合
方法:生成新号码 generateNewNum()
得到马上要为之服务的号码 fetchServiceNum() 注意:预防空指针异常,返回值设置为Integer
难点:由于方法 generateNewNum 与方法 CallServiceNum 访问相同的资源 numsQueue,所以考虑同步
*NumberMachine类
先构建普通对象,生成管理三种类型客户的方法:getCommonManager()、getVIPManager()、getQuickManager()
单例化
*ServiceWindow类
NumberMachine内部叫号的过程外部没必要了解,只需要对外提供一个开始工作的方法(start()),之后机器就
不停叫号!
注意:枚举的toString()方法
机器叫号时根据当前窗口的类型呼叫对应客户类型的号码。所以要有标记窗口类型的变量(用枚举最合适)
在判断条件非常多时,switch比if...else效率高
如何区别哪种类型的服务窗口或普通窗口的第几号窗口:要定义变量 windowID
可以把 windowID 和 CustomerType 作为构造方法参数来创建ServiceWindow对象,但不灵活、扩展性不好:不利于将来更改窗口号、更换服务窗口!所以用set(...)方法
服务时间随机生成在 Constant.MIN_SERVICE_TIME 与 Constant.MAX_SERIVCE_TIME 之间。注意将常量单独定义在类中的方法!
注意提取方法快捷操作:extract 的使用! commonService()的抽取使代码更有条理!但更好的做法是将VIP窗口、快速窗口作为普通窗口的子类,将逻辑与commonService()方法中不同的代码单独抽取为方法,并重写!可以最大限度地重用代码(因为quickService()与VIPService()方法的逻辑差不多)
测试类:
难点:异步随机生成各种类型的客户,生成各类型客户概率比例:VIP客户:普通客户:快速客户=1:6:3
通过定时器参数体现生成的三种类型客户的概率比
注意:fetchServiceNum() 是同步方法,要将打印语句放在这个方法后面,程序会流畅
只有当numsQueue中有号码时才取号码,否则返回null
VIP窗口和快速窗口为普通客户服务的情况:commonService方法中要写死“普通”,而 快速 和 VIP 窗口可以写 ct
两种单例模式的区别:在多线程程序中懒汉式单例必须加synchronized关键字(我自己写的时候就是用了这种“懒汉式”单例,因为程序中有多线程,导致生成了多个NumberMachine对象的实例)
多线程中锁中套锁容易死锁!
下面是程序的线程图解:
--------------------- android培训、java培训、期待与您交流! ----------------------
详细请查看:http://edu.csdn.net/heima
需求分析:
*银行有6个业务窗口,1-4号窗口是普通窗口,5号窗口为快速窗口,6号窗口是VIP窗口
*有三种对应类型的客户:VIP客户、普通客户、快速客户(办理如交水电费、电话费之类业务的客户)
*异步随机生成各种类型的客户,生成各类型客户概率比例:VIP客户:普通客户:快速客户=1:6:3
*客户办理业务所需时间有最大、最小值,在该范围内随机设定每个VIP客户及普通客户办理业务所需要的时间, 快速客户办理业务所需时间为最小值(办理业务的过 程可通过sleep())模拟
*各类型客户在其对应窗口依次办理业务(由窗口叫号)
*当VIP(6号)窗口和快速窗口没有客户等待办理业务时,可以办理普通客户业务。而一旦有普通客户等待办理业务, 优先处理对应客户的业务
*随机生成客户时间间隔及业务办理时间最大值、最小值
*不必实现GUI,只实现业务逻辑,可通过LOG方式展现程序运行结果
面向对象的分析设计
*有三种对应类型的客户:VIP客户、普通客户、快速客户(办理如交水电费、电话费之类业务的客户)
每个客户的表示方法:取号机产生一个号码。所以要有号码管理器对象(不断产生随机号码)
三类客户的号码编排是完全独立的,所以要有3个号码管理器对象,各自管理一类客户的排除号码
这3个号码管理器对象统一由一个号码机器管理(在号码机器选择要办理哪种客户类型的业务),这个号码机器在系统中始终只能有一个,设计成单例
*各类型客户在其对应窗口依次办理业务(窗口依次叫号)
窗口怎么知道叫哪个号码?它应该询问号码管理器。即:服务窗口每次找号码管理器获取当前要被服务的号码
画类图,使思路清晰:
2. 类的实现
*NumberManager类:
成员变量:存储上一个客户号码
等待服务的客户号码的队列集合
方法:生成新号码 generateNewNum()
得到马上要为之服务的号码 fetchServiceNum() 注意:预防空指针异常,返回值设置为Integer
难点:由于方法 generateNewNum 与方法 CallServiceNum 访问相同的资源 numsQueue,所以考虑同步
public synchronized Integer generateNewNum() { numsQueue.add(lastNum); return lastNum++; } public synchronized Integer CallServiceNum() { return numsQueue.remove(0); }
*NumberMachine类
先构建普通对象,生成管理三种类型客户的方法:getCommonManager()、getVIPManager()、getQuickManager()
单例化
*ServiceWindow类
NumberMachine内部叫号的过程外部没必要了解,只需要对外提供一个开始工作的方法(start()),之后机器就
不停叫号!
注意:枚举的toString()方法
public String toString() { switch (this) { //this的使用 case COMMON: return "普通"; case QUICK: return "快速"; case VIP: return name(); } return null; }
机器叫号时根据当前窗口的类型呼叫对应客户类型的号码。所以要有标记窗口类型的变量(用枚举最合适)
在判断条件非常多时,switch比if...else效率高
如何区别哪种类型的服务窗口或普通窗口的第几号窗口:要定义变量 windowID
可以把 windowID 和 CustomerType 作为构造方法参数来创建ServiceWindow对象,但不灵活、扩展性不好:不利于将来更改窗口号、更换服务窗口!所以用set(...)方法
服务时间随机生成在 Constant.MIN_SERVICE_TIME 与 Constant.MAX_SERIVCE_TIME 之间。注意将常量单独定义在类中的方法!
注意提取方法快捷操作:extract 的使用! commonService()的抽取使代码更有条理!但更好的做法是将VIP窗口、快速窗口作为普通窗口的子类,将逻辑与commonService()方法中不同的代码单独抽取为方法,并重写!可以最大限度地重用代码(因为quickService()与VIPService()方法的逻辑差不多)
private void commonService() { String windowName = "第 " + windowID + " 号 " + ct + " 窗口" ; System.out.println(windowName + " 正在叫号……"); Integer num = NumberMachine.getInstance().getCommonManager().fetchServiceNum(); if(null != num){ long startTime = System.currentTimeMillis(); int maxRand = Constant.MAX_SERIVCE_TIME - Constant.MIN_SERVICE_TIME; long serviceTime = new Random().nextInt(maxRand) + 1 + Constant.MIN_SERVICE_TIME; try { Thread.sleep(serviceTime); } catch (InterruptedException e) { e.printStackTrace(); } long costTime = System.currentTimeMillis() - startTime; System.out.println(windowName + " 为第 "+ num +" 个 " + ct + " 客户服务耗时 "+ (costTime/1000) +" 秒!"); } else { System.out.println(windowName + " 没有正在等待的客户!等待中……"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } }
测试类:
难点:异步随机生成各种类型的客户,生成各类型客户概率比例:VIP客户:普通客户:快速客户=1:6:3
通过定时器参数体现生成的三种类型客户的概率比
Executors.newScheduledThreadPool(1).scheduleAtFixedRate( new Runnable(){ @Override public void run() { int num = NumberMachine.getInstance().getVIPManager().generateNewNum(); System.out.println("第 " + num + " 个VIP客户正在等待……"); } }, 1, Constant.COMMONCUSTOMER_INTERVAL_TIME * 6, TimeUnit.SECONDS );
注意:fetchServiceNum() 是同步方法,要将打印语句放在这个方法后面,程序会流畅
只有当numsQueue中有号码时才取号码,否则返回null
VIP窗口和快速窗口为普通客户服务的情况:commonService方法中要写死“普通”,而 快速 和 VIP 窗口可以写 ct
两种单例模式的区别:在多线程程序中懒汉式单例必须加synchronized关键字(我自己写的时候就是用了这种“懒汉式”单例,因为程序中有多线程,导致生成了多个NumberMachine对象的实例)
多线程中锁中套锁容易死锁!
下面是程序的线程图解:
--------------------- android培训、java培训、期待与您交流! ----------------------
详细请查看:http://edu.csdn.net/heima
相关文章推荐
- (黑马程序员)银行业务调度系统
- 黑马程序员_银行业务调度系统
- 『黑马程序员』第十三话<银行业务调度系统>
- 黑马程序员-银行业务调度系统(改进版)
- <黑马程序员>破解月薪7K的面试题-银行业务调度系统
- 黑马程序员:银行业务调度系统
- 黑马程序员_银行业务调度系统
- 黑马程序员——银行业务调度系统
- 黑马程序员-Java基础学习之银行业务调度系统
- 黑马程序员_银行业务调度系统
- <黑马程序员>银行业务调度系统
- 黑马程序员-银行业务调度系统
- 黑马程序员——银行业务调度系统笔记
- 黑马程序员-java面试题-银行业务调度系统
- 黑马程序员----张老师 之 银行业务调度系统
- 黑马程序员------银行业务调度系统
- 黑马程序员-银行业务调度系统
- 黑马程序员-银行业务调度系统,对张老师视频的一些总结
- 黑马程序员_java之银行业务调度系统(很重要)
- 黑马程序员-银行业务调度系统