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

来源:互联网 发布:大宗商品电商 大数据 编辑:程序博客网 时间:2024/06/05 20:49

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

银行业务调度系统

题目:

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

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

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

异步随机生成各种类型的客户,生成各类型用户的概率比例为:VIP客户 :普通客户 :快速客户  =  1 :6 :3。

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

各类型客户在其对应窗口按顺序依次办理业务。 
当VIP(6号)窗口和快速业务(5号)窗口没有客户等待办理业务的时候,
这两个窗口可以处理普通客户的业务,而一旦有对应的客户等待办理业务的时候,则优先处理对应客户的业务。

随机生成客户时间间隔以及业务办理时间最大值和最小值自定,可以设置。
不要求实现GUI,只考虑系统逻辑实现,可通过Log方式展现程序运行结果。
------------------------------------------------------------------------------------------------------
 
对程序进行面向对象的分析:
 
有三种对应类型的客户:VIP客户,普通客户,快速客户 ,随机生成各种类型的客户,各类型客户在其对应窗口按顺序依次办理业务 。
当然,当快速窗口和VIP窗口木有接收到任务时,就办理普通业务!
 
每一个客户其实就是由银行的一个取号机器产生号码的方式来表示的。
所以,需要有一个号码管理器对象,让这个对象不断地随机产生号码,就等于随机生成了客户。
 
由于有三类客户,每类客户的号码编排都是完全独立的,所以,我想到本系统一共要产生三个号码管理器对象,各自管理一类用户的排队号码。
这三个号码管理器对象统一由一个号码机器进行管理,这个号码机器在整个系统中始终只能有一个,所以,它要被设计成单例。
 
各类型客户在其对应窗口按顺序依次办理业务 ,准确地说,应该是窗口依次叫号。
 窗口每次服务前找号码管理器获取当前要被服务的号码。
------------------------------------------------------------------------------------------------------
 
定义号码管理器类:NumberManager
按照面向对象的设计技巧,谁拥有数据谁就对外提供操作数据的方法,
人在黑马上画圆,圆心和半径的拥有者是圆,所以圆提供画圆的方法!


所以此类中需要定义客户取号的方法和窗口叫号的方法。

public class NumberManger {private int number=1;List<Integer> list=new ArrayList<Integer>();//用户拿号,因为有很多个用户拿号,所以使用synchronized同步锁,保证用户不会拿到同一个号码!public synchronized Integer generateNumber(){list.add(number);return number++;}//银行窗口拿号,因为有不同窗口拿号,所以使用synchronized同步锁,保证银行窗口对象不会同时拿到同一个用户public synchronized Integer fetchNumber(){if(list.size()>0){return list.remove(0);}return null;}}

定义号码管理机器类:NumberMachie
 因为号码管理机器只有一个,所以要将NumberMachine类设计成单例。
 
此类中定义三个成员变量分别指向三个NumberManager对象,分别表示普通、快速和VIP客户的号码管理器,定义三
 
个对应的方法来返回这三个NumberManager对象。


public class NumberMachine {//创建普通窗口NumberManger commonNumber = new NumberManger();//创建快速窗口NumberManger expressNumber = new NumberManger();//创建VIP窗口NumberManger vipNumber = new NumberManger();public NumberManger getCommonNumber() {return commonNumber;}public NumberManger getExpressNumber() {return expressNumber;}public NumberManger getVipNumber() {return vipNumber;}//采用单例模式,每类用户类型的号码机器都只能有一个!private NumberMachine(){};public static NumberMachine getInstance(){return instance;}private static NumberMachine instance=new NumberMachine();}

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

public enum CustomerType {COMMON,EXPRESS,VIP;public String toString(){switch (this) {case COMMON:return "普通";case EXPRESS:return "快速";case VIP:return name();}return null;}} 

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

public class ServiceWindow {private int windowId = 1;private CustomerType windowType = CustomerType.COMMON;public void setWindowId(int windowId) {this.windowId = windowId;}public void setWindowType(CustomerType windowType) {this.windowType = windowType;}public void start() {// 创建一个使用单个 worker 线程的 Executor,以无界队列方式来运行该线程Executors.newSingleThreadExecutor().execute(new Runnable() {public void run() {while(true){switch (windowType) {case COMMON:commonService();break;case EXPRESS:expressService();break;case VIP:vipService();break;}}}});}//普通服务public void commonService() {String windowName = "第" + windowId + "号" + windowType + "窗口";Integer serviceNumber = NumberMachine.getInstance().commonNumber.fetchNumber();System.out.println(windowName + "窗口正在获取普通服务");if (serviceNumber != null) {long beginTime = System.currentTimeMillis();//long serviceTime = (long) (Math.random() * Constants.MAXSERVETIME + Constants.MINSERVETIME);int serviceTime=new Random().nextInt(Constants.MAXSERVETIME)+Constants.MINSERVETIME;System.out.println(windowName + "正在为" + serviceNumber + "号普通用户服务!");try {Thread.sleep(serviceTime);} catch (InterruptedException e) {e.printStackTrace();}long endTime = System.currentTimeMillis() - beginTime;System.out.println(windowName + "为" + serviceNumber + "号普通用户服务,共花费"+ endTime / 1000 + "秒的时间!");} else {System.out.println(windowName + "没有获取到普通任务!先休息1S种吧!喝口茶,润润嗓子!");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}//快速服务public void expressService() {String windowName = "第" + windowId + "号" + windowType + "窗口";Integer serviceNumber = NumberMachine.getInstance().expressNumber.fetchNumber();System.out.println(windowName + "窗口正在获取快速服务");if (serviceNumber != null) {System.out.println(windowName + "正在为" + serviceNumber + "号快速用户服务!");try {Thread.sleep(Constants.MINSERVETIME);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(windowName + "为" + serviceNumber + "号快速用户服务,共花费"+ Constants.MINSERVETIME / 1000 + "秒的时间!");} else {System.out.println(windowName + "没有获取到快速任务");commonService();}}//vip服务public void vipService() {String windowName = "第" + windowId + "号" + windowType + "窗口";Integer serviceNumber = NumberMachine.getInstance().vipNumber.fetchNumber();System.out.println(windowName + "窗口正在获取vip服务");if (serviceNumber != null) {long beginTime = System.currentTimeMillis();int serviceTime=new Random().nextInt(Constants.MAXSERVETIME)+Constants.MINSERVETIME;System.out.println(windowName + "正在为" + serviceNumber + "号vip用户服务!");try {Thread.sleep(serviceTime);} catch (InterruptedException e) {e.printStackTrace();}long endTime = System.currentTimeMillis() - beginTime;System.out.println(windowName + "为" + serviceNumber+ "号vip用户服务,共花费" + endTime / 1000 + "秒的时间!");} else {System.out.println(windowName + "没有获取到vip任务!");commonService();}}} 

在定义ServiceWindow类时,需要用到常量,定义Constants类用来存放常量

public class Constants {//最大服务时间public static int MAXSERVETIME=10000;//最小服务时间public static int MINSERVETIME=1000;/**每个普通窗口服务一个客户的平均时间为5秒,一共有4个这样的窗口,也就是说银行的所有普通窗口合起来 * 平均1.25秒内可以服务完一个普通客户,再加上快速窗口和VIP窗口也可以服务普通客户,所以, * 1秒钟产生一个普通客户比较合理,*/public static int FETCH_INTEVAL_TIME=1;}

最后需要定义主函数,MainClass类
 需要建出4个普通窗口,1个快速窗口和一个VIP窗口。
 创建三个定时器,分别按照6:3:1的比例去创建普通客户、快速客户、新的VIP客户

public class MainClass {/** * @author 张熙韬 */public static void main(String[] args) {//产生四个普通窗口,并启动普通窗口的服务线程for (int i = 1; i <5; i++) {ServiceWindow commonwindow = new ServiceWindow();commonwindow.setWindowId(i);commonwindow.setWindowType(CustomerType.COMMON);commonwindow.start();}//产生一个快速窗口,并启动快速窗口的服务线程ServiceWindow expressWindow = new ServiceWindow();expressWindow.setWindowId(6);expressWindow.setWindowType(CustomerType.EXPRESS);expressWindow.start();//产生一个vip窗口,并启动vip窗口的服务线程ServiceWindow vipWindow = new ServiceWindow();vipWindow.setWindowId(1);vipWindow.setWindowType(CustomerType.VIP);vipWindow.start();//scheduleAtFixedRate创建并执行一个在给定初始延迟后首次启用的定期操作,后续操作具有给定的周期//定时生成普通用户,比例为:1:3:6Executors.newScheduledThreadPool(1).scheduleAtFixedRate(new Runnable() {public void run() {//普通用户拿号int number=NumberMachine.getInstance().getCommonNumber().generateNumber();System.out.println("第"+number+"号普通客户正在排队等待服务!");}},0, Constants.FETCH_INTEVAL_TIME, TimeUnit.SECONDS);//scheduleAtFixedRate创建并执行一个在给定初始延迟后首次启用的定期操作,后续操作具有给定的周期//定时生成快速用户,比例为:1:3:6Executors.newScheduledThreadPool(1).scheduleAtFixedRate(new Runnable() {public void run() {//快速用户拿号int number=NumberMachine.getInstance().getExpressNumber().generateNumber();System.out.println("第"+number+"号快速客户正在排队等待服务!");}},0, Constants.FETCH_INTEVAL_TIME*2, TimeUnit.SECONDS);//scheduleAtFixedRate创建并执行一个在给定初始延迟后首次启用的定期操作,后续操作具有给定的周期//定时生成vip用户,比例为:1:3:6Executors.newScheduledThreadPool(1).scheduleAtFixedRate(new Runnable() {public void run() {//VIP用户拿号int number=NumberMachine.getInstance().getVipNumber().generateNumber();System.out.println("第"+number+"号vip客户正在排队等待服务!");}},0, Constants.FETCH_INTEVAL_TIME*6, TimeUnit.SECONDS);}}

至此,通过学习,自己根据已有的思路,编写代码完全!
通过张老师的银行调度系统的学习,应该说收获很多!基本上把java多线程,枚举,面向对象设计,单例,集合,综合复习了一遍!
收获非常大!黑马是IT界的一颗璀璨的明星,我会为之不懈奋斗!成为一个优秀的黑马人!

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


原创粉丝点击