黑马程序员_7K面试题之银行业务调度系统

来源:互联网 发布:日期提醒软件app 编辑:程序博客网 时间:2024/06/10 06:08

            银行业务调度系统

一、概述

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

 

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

 

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

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

 

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

   

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

 

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

 

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

 

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


二、需求分析

由题目可以了解到不管是客户还是服务窗口,他们操作的都是同一个取票机,当客户来到银行办理业务的时候,会到取票机器那里取得一张号码,同时该号码会存储在相对应的取票器中,这时就会有对应的窗口向对应的取票器中读取存入的号码,从而有序地对用户进行操作。


       由需求可以知道,我们在一台取票机中得有三个取票器,分别管理着普通客户、快速客户和VIP客户的取号,同时窗口也分为普通窗口、快速窗口和VIP窗口,规定普通窗口只能办理普通客户的手续,VIP客户可以办理VIP客户手续,如果在没有VIP客户的时候,也可以办理普通客户,快速窗口也一样,在没有快速客户的时候,也可以办理普通客户的手续,如此分析,则有取票机的结构应为这样:


一个取票机里面有三个取票器,VIP窗口和快速窗口的操作功能是一样,均为“做完自己的事,再忙其他的事”;基本流程图如下:


普通窗口和VIP、快速窗口则不一样,其基本流程图如下:


到此,几个取票器之间的基本关系就可以确立了下来了。在需求里面有提到客户服务时间与客服产生时间,这里使用线程的sleep方法来模拟为客户的服务的时间,使用jdk5的新特性来模拟客户产生的过程,在这个系统中,个人觉得的就是类与类之间的关系太过于复杂了,所以按照了个人的理解画出了类与类之间的关系图。自定义的类有:

NunberManage:产生客服和取出客服的取票器

NumberMachine:模拟了一个取票机,里面包含了三个取票器

ServiceWindow :模拟窗口去操作取票机,服务不同的客户

MainClass:初始化各种窗口,以及设计了客户已1:6:3来到银行办理业务

CustomerService:存储在各个类中要使用到的常量

WindowType:枚举类,存了三种窗口类型的对象。

很据我自己的理解得出的他们之间的关系;:


三、各个类的设计

NumberManage类的设计:

该类提供了两个方法:

getNewNumber():当有客户取服务号码的时候,产生一个号码,将此号码返回给客户,使得客服指导知己的号码,同时将这一号码存储在一个容器中,以便服务窗口能取到号码,并为相应的客户服务。

fetchNumber():为窗口调用,窗口取得集合中的号码,并为该号码对应的客户服务。

由于这里设计到了两个函数同时操作一个对象(集合),所以这里要使用同步锁,使得在某一时刻只能有一个方法区操作集合,避免了异常的产生。

该类的设计的源码为:


package cn.itcast.bank;import java.util.ArrayList;import java.util.List;//这里产生为每一中类型的取票器提供两种方法,//提供为客户取票和窗口取票两种方法public class NumberManage {//使用一个集合,将客户产生的号码放入该集合中,方便窗口取得该号码,为客户服务  private  List<Integer> NumberArr = new ArrayList<Integer>();    //在定义个变量,用来返回客户的号码  private int lastNumber =0;public synchronized Integer getNewNumber(){ //这里是两个函数同时操作同一个集合,为了避免产生异常,使用同步函数NumberArr.add(++lastNumber);   //客服取票,同时将客户所取得的号码存入集合中return lastNumber;}public synchronized Integer fetchNumber(){if(NumberArr.size() > 0){ //得闲判断是否有需要服务的客户returnNumberArr.remove(0);}else{return null;}}}

NumberMachine类的设计:

该类模拟了一个取票机,保证该取票机只能有一个,同时也要得到该取票机中的三种取票器,

所以该类的设计就是创建NumberManage类的对象,对外提供获取该类对象的方法,同时,使用单例设计模式让本类永远都只能有一个实例对象:

该类源码为:

package cn.itcast.bank;/* * 该类模拟了一个取票机,该取票机里有三个取票器,分别是普通客户取票器、VIP客户取票器和快速客户取票器 *  * 三个取票器有各自的NumberManage *  * 为了产生避免产生多个相同的号码,所以这里采用了单例设计模式,也就是这里只有一个取票机 *  *  * */public class NumberMachine {//创建三个取票器//普通客服取票器private NumberManage commonCustomer = new NumberManage();//VIP客户取票器private NumberManage VIPCustomer = new NumberManage();//快速客户取票器private NumberManage fastCustomer = new NumberManage();public NumberManage getCommonCustomer() {return commonCustomer;}public NumberManage getVIPCustomer() {return VIPCustomer;}public NumberManage getFastCustomer() {return fastCustomer;}//控制本类永远只有一个对象,单例设计模式private NumberMachine(){};private static NumberMachine instance = new NumberMachine();public static NumberMachine getInstance(){return instance;}}


ServiceWindow类的设计:

该类可以为各种类型的客户提供服务,也就是说这个类可以模拟不同的窗口,并为不同的客户提供服务,这里具体有什么样的窗口,还要由MainClass类中指定,这里指定了什么样的窗口应该为什么样的客户服务,使用jdk1.5的新特性,开启一个线程来执行取票任务,使用循环,不停地取票,并判断当前窗口是那种类型的窗口,使用当前窗口去执行对应的取票任务(VIP窗口在VIP取票器中取票,快速窗口在快速取票器中取票。。。。),对于VIP取票和快速取票,如果当前没有VIP客户,则VIP窗口将会为普通客户服务,快速窗口也一样,

setType:用来设置当前窗口是什么类型的,

setWinNumber:用来设置当前窗口是第几个窗口。


start();窗口开启,开始服务


CommCustomer();为普通客户提供服务,没有普通客户时,休息1s,有,为该客户服务,并在一定时间内不为其他客户服务(线程睡眠一端时间);

FastCustomer();为快速客户提供服务,有快速客户时,为快速客服提供服务,在服务期间也不为其他客户提供服务(线程睡眠一段时间),如果没有快速客户,则该快速窗口就会为普通客户提供服务,此时有普通客户,为普通客户提供服务,没有,休息1s,再继续去取快速客户,如此循环。

VipCustomer();该方法的功能和FastCustomer的功能相似;


该类的源码实现:

package cn.itcast.bank;import java.util.Random;import java.util.concurrent.Executors;//模拟服务窗口public class ServiceWindow {//初始化窗口WindowType type = WindowType.COMMON;//初始化窗口private int winNumber;   //开始取票public void setType(WindowType type) {this.type = type;}public void setWinNumber(int winNumber) {this.winNumber = winNumber;}public void start(){//开启一个线程来执行窗口取票Executors.newSingleThreadExecutor().execute(new Runnable() {@Overridepublic void run() {// TODO Auto-generated method stubwhile(true){switch (type) {case COMMON: //如果是普通窗口ConmmNumber();break;case FAST:FastNumber();break;case VIP:VipNumber();break;}}}});}protected void ConmmNumber() {// TODO Auto-generated method stub//获得取票机中取票器NumberManage common = NumberMachine.getInstance().getCommonCustomer();//获取该取票器中的号码Integer CustomerNumber =  common.fetchNumber();if(CustomerNumber != null){//取到号码,为该客户服务System.out.println("第"+winNumber+"号"+type+"窗口正在为"+CustomerNumber+"号普通用户服务");//服务期间,不能服务其他客户,让该线程睡眠一段时间,int Time = CustomerService.WINDOW_SERVICE_MAX_TIME-CustomerService.WINDOW_SERVICE_MIN_TIME; int currentTime = new Random().nextInt(Time)+1 + CustomerService.WINDOW_SERVICE_MIN_TIME;try {Thread.sleep(currentTime);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println("完成对"+CustomerNumber+"号普通客户的服务,总耗时"+currentTime/1000+"s");}else{System.out.println("第"+winNumber+"号"+type+"窗口没有取到普通客户,休息1s");try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}protected void FastNumber() {// TODO Auto-generated method stub//获得取票机中取票器NumberManage common = NumberMachine.getInstance().getFastCustomer();//获取该取票器中的号码Integer CustomerNumber =  common.fetchNumber();if(CustomerNumber != null){//取到号码,为该客户服务System.out.println("第"+winNumber+"号"+type+"窗口正在为"+CustomerNumber+"号快速客户服务");//服务期间,不能服务其他客户,让该线程睡眠一段时间,//int Time = CustomerService.WINDOW_SERVICE_MAX_TIME-CustomerService.WINDOW_SERVICE_MIN_TIME;     //   int currentTime = new Random().nextInt(CustomerService.WINDOW_SERVICE_MIN_TIME)+1;try {Thread.sleep(CustomerService.WINDOW_SERVICE_MIN_TIME);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println("完成对"+CustomerNumber+"号快速客户的服务,总耗时"+CustomerService.WINDOW_SERVICE_MIN_TIME/1000+"s");}else{System.out.println("第"+winNumber+"号"+type+"窗口没有取到"+type+"客户,可以为普通客户服务");     ConmmNumber();}}protected void VipNumber() {// TODO Auto-generated method stub//获得取票机中取票器NumberManage common = NumberMachine.getInstance().getVIPCustomer();//获取该取票器中的号码Integer CustomerNumber =  common.fetchNumber();if(CustomerNumber != null){//取到号码,为该客户服务System.out.println("第"+winNumber+"号"+type+"窗口正在为"+CustomerNumber+"号VIP客户服务");//服务期间,不能服务其他客户,让该线程睡眠一段时间,int Time = CustomerService.WINDOW_SERVICE_MAX_TIME-CustomerService.WINDOW_SERVICE_MIN_TIME;         int currentTime = new Random().nextInt(Time)+1 + CustomerService.WINDOW_SERVICE_MIN_TIME;try {Thread.sleep(currentTime);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println("完成对"+CustomerNumber+"号VIP客户的服务,总耗时"+currentTime/1000+"s");}else{System.out.println("第"+winNumber+"号"+type+"窗口没有取到"+type+"客户,可以为普通客户服务");     ConmmNumber();}}}

MainClass类的设计:

该类就做了一些初始化啊,这里就初始化了五个普通窗口,一个快速窗口,一个VIP窗口,并产生三个新线程去模拟三种不同的客户的产生的情况,并实现

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

该类源码:

package cn.itcast.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 Commwindow = new ServiceWindow();  Commwindow.setWinNumber(i);  Commwindow.start();}//开启一个VIP窗口ServiceWindow Vipwindow = new ServiceWindow();Vipwindow.setType(WindowType.VIP);Vipwindow.setWinNumber(1);Vipwindow.start();//开启一个快速窗口ServiceWindow Fastwindow = new ServiceWindow();Fastwindow.setType(WindowType.FAST);Fastwindow.setWinNumber(1);Fastwindow.start();//开启窗口,先在就是上班时间,该有客户来办理业务了,由于三种客户之间是没有任何联系的,所以每一种客户要使用单独的线程来控制//普通客户Executors.newScheduledThreadPool(1).scheduleAtFixedRate(                new Runnable() {@Overridepublic void run() {// TODO Auto-generated method stubInteger Customer =NumberMachine.getInstance().getCommonCustomer().getNewNumber();System.out.println("第"+Customer+"号普通客户正在等待办理业务");}},0,CustomerService.HOW_TIME_ADDCUSTOMER,TimeUnit.SECONDS);//VIP客户Executors.newScheduledThreadPool(1).scheduleAtFixedRate(                  new Runnable() {@Overridepublic void run() {// TODO Auto-generated method stubInteger Customer =NumberMachine.getInstance().getVIPCustomer().getNewNumber();System.out.println("第"+Customer+"号VIP客户正在等待办理业务");}},0,CustomerService.HOW_TIME_ADDCUSTOMER * 6,TimeUnit.SECONDS);//快速客户Executors.newScheduledThreadPool(1).scheduleAtFixedRate(                new Runnable() {@Overridepublic void run() {// TODO Auto-generated method stubInteger Customer =NumberMachine.getInstance().getFastCustomer().getNewNumber();System.out.println("第"+Customer+"号快速客户正在等待办理业务");}},0,CustomerService.HOW_TIME_ADDCUSTOMER * 2,TimeUnit.SECONDS);} }

对于CustomerService类存储的就是一些在其他类中的常量:

package cn.itcast.bank;public class CustomerService {//一个窗口为客户服务的最大时间为public static final int WINDOW_SERVICE_MAX_TIME = 10000;//一个窗口为客户服务的最大时间为public static final int WINDOW_SERVICE_MIN_TIME = 1000;//设置多长时间增加一个客户public static final int HOW_TIME_ADDCUSTOMER = 1;}

WindowType是一个枚举类,该枚举类有三个实例对象,分别是:COMMON,VIP,FAST,他们分别代表了窗口的类型为:普通类型,VIP类型和快速窗口类型,这里覆盖了他们的toString方法,

package cn.itcast.bank;public enum WindowType {COMMON,VIP,FAST;@Overridepublic String toString(){switch (this) {case COMMON:   return "普通";case VIP:return name();case FAST:return "快速";default:break;}return null;}}












0 0
原创粉丝点击