模拟实现银行业务调度系统逻辑,具体需求如下:
银行内有6个业务窗口,1 - 4号窗口为普通窗口,5号窗口为快速窗口,6号窗口为VIP窗口。
有三种对应类型的客户:VIP客户,普通客户,快速客户(办理如交水电费、电话费之类业务的客户)。
异步随机生成各种类型的客户,生成各类型用户的概率比例为:
VIP客户 :普通客户 :快速客户 = 1 :6 :3。
客户办理业务所需时间有最大值和最小值,在该范围内随机设定每个VIP客户以及普通客户办理业务所需的时间,快速客户办理业务所需时间为最小值(提示:办理业务的过程可通过线程Sleep的方式模拟)。
各类型客户在其对应窗口按顺序依次办理业务。
当VIP(6号)窗口和快速业务(5号)窗口没有客户等待办理业务的时候,这两个窗口可以处理普通客户的业务,而一旦有对应的客户等待办理业务的时候,则优先处理对应客户的业务。
随机生成客户时间间隔以及业务办理时间最大值和最小值自定,可以设置。
不要求实现GUI,只考虑系统逻辑实现,可通过Log方式展现程序运行结果。
我们知道客户去银行办理业务,首先要去取号机取号,然后等待窗口叫号,那么窗口是通过什么叫号的呢,就是根据取号机内部产生和维护的不同的业务队列来完成的
所以
涉及的对象有:业务窗口、客户、取号机、业务类型以及取号机内部维护的业务队列
为了简化设计,用字符串形式代替客户信息,主要实现系统逻辑为主
采用枚举的方式,创建3个实例分别表示普通业务、快速业务、VIP业务
内部维护一个集合用来存放队列中的客户信息
以及一个整型变量用来表示当天的客户队列号
实现加入一个客户到队列的方法
以及从队列中取出一个客户的方法(即叫号过程)
简化编程,我们将取号机设计成一个单例
内部维护三个不同业务类型的队列
对外提供取号方法给用户
提供获取队列方法给业务窗口
业务窗口属性有:业务类型及窗口编号
对外提供开始业务的方法供银行调度
在对业务窗口进行设计的时候发现,虽然各窗口同属一类,但在提供服务的过程不尽相同,所以考虑的两种实现方式
第一种就是考虑到在开展业务的时候各窗口的代码有不同之处,所以考虑用这种方式来设计,将不同的业务类型的窗口分配到不同的类
第二种是直接将所有业务类型的服务代码写在同一个类中
由于不太懂设计模式,个人的感觉是,这里主要实现的是系统逻辑,所以每个窗口的服务代码差异并没有想象的大,故采用第二种方式
如果是一个比较系统的需要长期维护的项目,我会采用第一种,确保每个类的单一功能
业务类型BusinessType类: 1: /** 2: * 业务类型 3: * @author Shawn 4: * 5: */ 6: public enum BusinessType { 7: GENERAL,//普通业务类型 8: QUICK,//快速业务类型 9: VIP;//VIP业务类型 10: 11: @Override 12: public String toString() { 13: switch(this){ 14: case GENERAL: 15: return "普通"; 16: case QUICK: 17: return "快速"; 18: case VIP: 19: return "VIP"; 20: } 21: return null; 22: } 23: } 用户队列Queue类: 1: /** 2: * 用户队列 3: * @author Shawn 4: * 5: */ 6: public class Queue { 7: 8: private BusinessType businessType;//队列的业务类型 9: private int customerNum = 1;//记录用户队列号 10: List<String> queue = new LinkedList<String>();//队列载体 11: 12: public Queue(BusinessType businessType) { 13: super(); 14: this.businessType = businessType; 15: } 16: 17: //产生新的号码,加入到队列 18: public synchronized String generateNewCustomer(){ 19: String name = businessType+"客户_"+(customerNum++)+"号"; 20: if(queue.add(name)) 21: return name; 22: else 23: return null; 24: } 25: 26: //从队列中取出第一个客户 27: public synchronized String getCustomer(){ 28: if(!isEmpty()) 29: return queue.remove(0); 30: else 31: return null; 32: } 33: 34: //判断队列是否为空,即是否有客户等待业务 35: public synchronized boolean isEmpty(){ 36: if(queue.size() > 0) 37: return false; 38: else 39: return true; 40: } 41: } 取号机TicketMachine类: 1: /** 2: * 取号机 3: * @author Shawn 4: * 5: */ 6: public class TicketMachine { 7: 8: //内部维护的三个业务队列 9: private Queue generalQueue = new Queue(BusinessType.GENERAL); 10: private Queue quickQueue = new Queue(BusinessType.QUICK); 11: private Queue vipQueue = new Queue(BusinessType.VIP); 12: 13: //获取相关业务队列的接口 14: public Queue getQueue(BusinessType businessType){ 15: switch(businessType){ 16: case GENERAL: 17: return generalQueue; 18: case QUICK: 19: return quickQueue; 20: case VIP: 21: return vipQueue; 22: } 23: return null; 24: } 25: 26: //针对不同业务,加入新的客户到对应队列 27: public String generateTicket(BusinessType businessType){ 28: switch(businessType){ 29: case GENERAL: 30: return generalQueue.generateNewCustomer(); 31: case QUICK: 32: return quickQueue.generateNewCustomer(); 33: case VIP: 34: return vipQueue.generateNewCustomer(); 35: } 36: return null; 37: } 38: //单例实现 39: private TicketMachine(){} 40: private static TicketMachine machineInstance = new TicketMachine(); 41: public static TicketMachine getInstance(){ 42: return machineInstance; 43: } 44: } 业务窗口Windows类: 1: /** 2: * 业务窗口 3: * @author Shawn 4: * 5: */ 6: public class Windows { 7: private BusinessType businessType;//窗口业务类型 8: private int winNum;//窗口编号 9: private boolean available = false;//窗口开放状态 10: 11: public Windows(BusinessType businessType,int winNum) { 12: super(); 13: this.businessType = businessType; 14: this.winNum = winNum; 15: } 16: 17: //开始业务 18: public void start(){ 19: available = true; 20: System.out.println(this+"开始服务!"); 21: 22: //创建新的线程开始不同窗口的业务 23: ExecutorService pool = Executors.newSingleThreadExecutor(); 24: pool.execute(new Runnable(){ 25: public void run(){ 26: switch(businessType){ 27: case GENERAL: 28: while(available){ 29: generalService(); 30: } 31: case QUICK: 32: while(available){ 33: quickService(); 34: } 35: case VIP: 36: while(available){ 37: vipService(); 38: } 39: } 40: } 41: }); 42: } 43: //普通业务窗口服务过程 44: private void generalService(){ 45: //普通业务只需要获得普通用户队列 46: Queue queue = TicketMachine.getInstance().getQueue(BusinessType.GENERAL); 47: //如果队列不为空,则开始叫号并模拟服务 48: if(!queue.isEmpty()){ 49: String name = queue.getCustomer(); 50: System.out.println(this+"正在为 "+name+"服务~"); 51: int time = generalCustomerServicing(); 52: //System.out.println(this+"服务完毕,耗时"+time+"秒"); 53: } 54: else{ 55: //System.out.println(this+"正在等待客户..."); 56: try { 57: Thread.sleep(1000); 58: } catch (InterruptedException e) { 59: // TODO Auto-generated catch block 60: e.printStackTrace(); 61: } 62: } 63: } 64: //快速窗口业务服务过程 65: private void quickService(){ 66: //快速窗口需要得到快速队列以及普通队列 67: Queue quickQueue = TicketMachine.getInstance().getQueue(BusinessType.QUICK); 68: Queue generalQueue = TicketMachine.getInstance().getQueue(BusinessType.GENERAL); 69: 70: //首先判断快速队列 71: if(!quickQueue.isEmpty()){ 72: String name = quickQueue.getCustomer(); 73: System.out.println(this+"正在为 "+name+"服务~"); 74: int time = quickCustomerServicing(); 75: //System.out.println(this+"服务完毕,耗时"+time+"秒"); 76: } 77: //若快速队列没有等待客户,则考虑普通队列 78: else if(!generalQueue.isEmpty()){ 79: String name = generalQueue.getCustomer(); 80: System.out.println(this+"正在为 "+name+"服务~"); 81: int time = generalCustomerServicing(); 82: //System.out.println(this+"服务完毕,耗时"+time+"秒"); 83: } 84: else{ 85: //System.out.println(this+"正在等待客户..."); 86: try { 87: Thread.sleep(1000); 88: } catch (InterruptedException e) { 89: // TODO Auto-generated catch block 90: e.printStackTrace(); 91: } 92: } 93: } 94: //vip窗口业务服务过程 95: private void vipService(){ 96: //vip窗口需要得到的vip队列以及普通队列 97: Queue vipQueue = TicketMachine.getInstance().getQueue(BusinessType.VIP); 98: Queue generalQueue = TicketMachine.getInstance().getQueue(BusinessType.GENERAL); 99: 100: //如果vip队列不为空,则取出vip客户处理 101: if(!vipQueue.isEmpty()){ 102: String name = vipQueue.getCustomer(); 103: System.out.println(this+"正在为 "+name+"服务~"); 104: int time = vipCustomerServicing(); 105: //System.out.println(this+"服务完毕,耗时"+time+"秒"); 106: } 107: //若vip队列为空,则考虑普通队列 108: else if(!generalQueue.isEmpty()){ 109: String name = generalQueue.getCustomer(); 110: System.out.println(this+"正在为 "+name+"服务~"); 111: int time = generalCustomerServicing(); 112: //System.out.println(this+"服务完毕,耗时"+time+"秒"); 113: } 114: else{ 115: //System.out.println(this+"正在等待客户..."); 116: try { 117: Thread.sleep(1000); 118: } catch (InterruptedException e) { 119: // TODO Auto-generated catch block 120: e.printStackTrace(); 121: } 122: } 123: 124: } 125: //服务普通客户的模拟时间 126: private int generalCustomerServicing(){ 127: int time = new Random().nextInt( 128: Constants.MAX_SERVICE_TIME-Constants.MIN_SERVICE_TIME)+ 129: Constants.MIN_SERVICE_TIME; 130: try { 131: Thread.sleep(time*1000); 132: } catch (InterruptedException e) { 133: // TODO Auto-generated catch block 134: e.printStackTrace(); 135: } 136: return time; 137: } 138: //服务快速客户的模拟时间 139: private int quickCustomerServicing(){ 140: int time = Constants.MIN_SERVICE_TIME; 141: try { 142: Thread.sleep(time*1000); 143: } catch (InterruptedException e) { 144: // TODO Auto-generated catch block 145: e.printStackTrace(); 146: } 147: return time; 148: } 149: //服务vip客户的模拟时间 150: private int vipCustomerServicing(){ 151: int time = new Random().nextInt( 152: Constants.MAX_SERVICE_TIME-Constants.MIN_SERVICE_TIME)+ 153: Constants.MIN_SERVICE_TIME; 154: try { 155: Thread.sleep(time*1000); 156: } catch (InterruptedException e) { 157: // TODO Auto-generated catch block 158: e.printStackTrace(); 159: } 160: return time; 161: } 162: 163: @Override 164: public String toString() { 165: // TODO Auto-generated method stub 166: return businessType+"窗口"+winNum+"号"; 167: } 168: } 最后,统一维护的常量类,以及测试代码 1: /** 2: * 统一维护的常量信息 3: * @author Shawn 4: * 5: */ 6: public class Constants { 7: 8: //客户服务的最大时间 10s 9: public static int MAX_SERVICE_TIME = 10; 10: //客户服务的最小时间 5s 11: public static int MIN_SERVICE_TIME = 5; 12: 13: //产生普通客户的间隔时间 1s 14: public static int COMMON_ITTERVAL_TIME = 1; 15: } 1: public class MainClass { 2: 3: /** 4: * 测试代码 5: * @param args 6: */ 7: public static void main(String[] args) { 8: ScheduledExecutorService timer = null; 9: 10: //建立普通窗口 11: for(int i = 1 ; i <= 4 ; i ++){ 12: new Windows(BusinessType.GENERAL,i).start(); 13: } 14: //建立快速窗口 15: new Windows(BusinessType.QUICK,1).start(); 16: //建立VIP窗口 17: new Windows(BusinessType.VIP,1).start(); 18: //普通用户拿票 19: timer = Executors.newScheduledThreadPool(1); 20: timer.scheduleAtFixedRate( 21: new Runnable(){ 22: public void run(){ 23: String name = TicketMachine.getInstance().generateTicket(BusinessType.GENERAL); 24: //System.out.println(name + "正在等待服务..."); 25: } 26: }, 27: 1, 28: Constants.COMMON_ITTERVAL_TIME, 29: TimeUnit.SECONDS); 30: //快速用户拿票 31: timer = Executors.newScheduledThreadPool(1); 32: timer.scheduleAtFixedRate( 33: new Runnable(){ 34: public void run(){ 35: String name = TicketMachine.getInstance().generateTicket(BusinessType.QUICK); 36: //System.out.println(name + "正在等待服务..."); 37: } 38: }, 39: 1, 40: Constants.COMMON_ITTERVAL_TIME*2, 41: TimeUnit.SECONDS); 42: 43: //普通用户拿票 44: timer = Executors.newScheduledThreadPool(1); 45: timer.scheduleAtFixedRate( 46: new Runnable(){ 47: public void run(){ 48: String name = TicketMachine.getInstance().generateTicket(BusinessType.VIP); 49: //System.out.println(name + "正在等待服务..."); 50: } 51: }, 52: 1, 53: Constants.COMMON_ITTERVAL_TIME*6, 54: TimeUnit.SECONDS); 55: } 56: } 总结 基本实现了银行取号调度的系统逻辑