Main.java
/** * 需求:银行业务调度系统 * 模拟实现银行业务调度系统逻辑,具体需求如下: * 1.银行内有6个业务窗口,1 - 4号窗口为普通窗口,5号窗口为快速窗口,6号窗口为VIP窗口。 * 2.有三种对应类型的客户:VIP客户,普通客户,快速客户(办理如交水电费、电话费之类业务的客户)。 * 3.异步随机生成各种类型的客户,生成各类型用户的概率比例为: * 4.VIP客户 :普通客户 :快速客户 = 1 :6 :3。 * 5.客户办理业务所需时间有最大值和最小值,在该范围内随机设定每个VIP客户以及普通客户办理业务所需的时间,快 * 速客户办理业务所需时间为最小值(提示:办理业务的过程可通过线程Sleep的方式模拟)。 * 6.各类型客户在其对应窗口按顺序依次办理业务。 * 7.当VIP(6号)窗口和快速业务(5号)窗口没有客户等待办理业务的时候,这两个窗口可以处理普通客户的业务,而 * 一旦有对应的客户等待办理业务的时候,则优先处理对应客户的业务。 * 8.随机生成客户时间间隔以及业务办理时间最大值和最小值自定,可以设置。 * 9.不要求实现GUI,只考虑系统逻辑实现,可通过Log方式展现程序运行结果。 * * 思路 * 系统分析(抽取对象和对象的功能): * 1.从整个业务逻辑来说,整个系统分为 3 种对象,银行窗口、银行客户、银行自动排队机 * 2.整个业务用上面的对象来描述就是客户先到自动排队机按照自己的业务类别取号,拿到号后等着窗口呼叫 * 3.自动排队机可以给客户依顺序分配一个号码,然后把该客户添加到相应的业务种类的队列里,自动排队机还可 * 以给银行业务窗口分配对应类型的客户 * 4.银行客户窗口主要的功能就是从自动排队机里面获取一个客户,处理客户的业务,再从自动排队机里面获取一 * 个客户 * * 步骤: * 1.定义上述各个对象的接口和接口中的功能 * 2.用具体的类实现这些接口 * 3.在 main 函数中使用这些对象实现业务 * 1.创建 ACDSyste 对象 * 2.创建窗口对象,但是 6 个窗口是异步工作的,所以需要6个线程来描述,所以窗口需要实现 Runnable 接口, * 因为每个窗口都要使用 ACDSystem 来呼叫客户,所以在创建窗口对象的时候需要传递一个 ACDSystem 对象。 * 3.创建银行客户,并调用客户到自动排队机排队的方法 * 4.完善 main 函数中涉及到的类,和接口,这一步只是让他们语法上都对,实现 main 函数中用到的函数 * 5.从上至下完善 main 函数用到的类和类的函数,不对各个类中的内部函数实现 * 6.实现各个类中的内部函数 * * 总结: * 1.先从需求建立需求模型——分析需求 * 2.再从需求模型建立系统模型——建立对象模型 * 3.再把系统模型用代码实现——实现对象模型 * 4.根据变化重构——重构 */ package cn.itcast.project.bank; import java.util.Random; /** * @class: Main * @package: cn.itcast.project.bank * @description: TODO * @author: vivianZhao * @date: 2013-7-25 下午4:10:47 * @version: 1.0 */ public class Main { /** * @method: main * @description: TODO * @param args * @return: void * @author: vivianZhao * @date: 2013-7-25 下午4:10:48 * @version: 1.0 */ public static void main(String[] args) { // TODO Auto-generated method stub // 创建 ACDSystem ACDSystem acdSystem = new ICBCACDSystem(); // 创建银行窗口 final int numberBankWindows = 6; Thread[] bankWindows = new Thread[numberBankWindows]; for (int i = 0; i < numberBankWindows; i++) { if (i < 4) { bankWindows[i] = new Thread(new ICBCWindow(acdSystem, BusinessType.General, i)); } else if (i < 5) { bankWindows[i] = new Thread(new ICBCWindow(acdSystem, BusinessType.Fast, i)); } else { bankWindows[i] = new Thread(new ICBCWindow(acdSystem, BusinessType.Vip, i)); } bankWindows[i].start(); System.out.println("银行 " + i + " 号窗口开始办理业务"); } // 使用主线程创建银行客户 Random random = new Random(System.currentTimeMillis()); for (int i = 0; i < 100; i++) { // 随机获取客户业务类型 BusinessType businessType = getRandomBusinessType(random); // 产生银行客户, 并根据业务类型排队 BankClient bankClient = new ICBCClient(i); int number = bankClient.queue(acdSystem, businessType); System.out.println(i + " 号 " + businessType.name() + " 类型客户排队,拿到 " + number + " 号"); try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } private static BusinessType getRandomBusinessType(Random random) { int numberBusinessType = random.nextInt(10); if (numberBusinessType < 6) { return BusinessType.General; } else if (numberBusinessType < 9) { return BusinessType.Fast; } else { return BusinessType.Vip; } } } enum BusinessType { General, Fast, Vip; }
BankWindow 接口
package cn.itcast.project.bank; /** * @interface: BankWindow * @package: cn.itcast.project.bank * @description: TODO * @author: vivianZhao * @date: 2013-7-25 下午4:11:27 * @version: 1.0 */ public interface BankWindow { BankClient callClientUseACD(); void dealCurrentClientBusiness(); BusinessType getBusinessType(); }
BankClient 接口
package cn.itcast.project.bank; /** * @interface: BankClient * @package: cn.itcast.project.bank * @description: TODO * @author: vivianZhao * @date: 2013-7-25 下午4:13:13 * @version: 1.0 */ public interface BankClient { // 客户排队之后可以获得当前业务队列有多少人 int queue(ACDSystem acdSystem, BusinessType businessType); long getBusinessTime(); long getClientNo(); BusinessType getBusinessType(); }
ACDSystem 接口, ACDSystem 是自动呼叫分配器系统
package cn.itcast.project.bank; /** * @interface: ACDSystem * @package: cn.itcast.project.bank * @description: TODO * @author: vivianZhao * @date: 2013-7-25 下午4:14:53 * @version: 1.0 */ public interface ACDSystem { int addClient(BankClient bankClient); BankClient removeClient(BankWindow bankWindow); }
ICBCWindow
package cn.itcast.project.bank; /** * @class: ICBCWindow * @package: cn.itcast.project.bank * @description: TODO * @author: vivianZhao * @date: 2013-7-25 下午5:18:31 * @version: 1.0 */ public class ICBCWindow implements BankWindow, Runnable { private ACDSystem acdSystem; private BusinessType businessType; private BankClient currentClient; private int windowNo; public ICBCWindow(ACDSystem acdSystem, BusinessType businessType, int windowNo) { super(); this.acdSystem = acdSystem; this.businessType = businessType; this.windowNo = windowNo; } /* * (non-Javadoc) * * @see cn.itcast.project.bank.BankWindow#callClientUseACD() */ @Override public BankClient callClientUseACD() { // TODO Auto-generated method stub currentClient = null; currentClient = acdSystem.removeClient(this); return null; } /* * (non-Javadoc) * * @see cn.itcast.project.bank.BankWindow#dealCurrentClientBusiness() */ @Override public void dealCurrentClientBusiness() { // TODO Auto-generated method stub try { Thread.sleep(currentClient.getBusinessTime()); System.out.println(windowNo + " 号窗口办理 " + currentClient.getClientNo() + " 号 " + currentClient.getBusinessType().name() + " 类型客户业务耗时 " + currentClient.getBusinessTime() / 1000 + "s"); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } @Override public BusinessType getBusinessType() { // TODO Auto-generated method stub return businessType; } @Override public void run() { // TODO Auto-generated method stub while (true) { callClientUseACD(); if (currentClient != null) { dealCurrentClientBusiness(); } } } }
ICBCClient
package cn.itcast.project.bank; public class ICBCClient implements BankClient { static final long BusinessTimeMax = 10000; static final long BusinessTimeMin = 1000; private long businessTime; private int clientNo; private BusinessType businessType; public ICBCClient(int clientNo) { // TODO Auto-generated constructor stub this.clientNo = clientNo; } @Override public int queue(ACDSystem acdSystem, BusinessType businessType) { // TODO Auto-generated method stub // 设置客户业务消耗的时间的随机数,如果是快速业务,就直接设置为最少耗时 if (businessType == BusinessType.Fast) { businessTime = BusinessTimeMin; }else { businessTime = (long) (Math.random() * (BusinessTimeMax - BusinessTimeMin) + BusinessTimeMin); } this.businessType = businessType; // 使用 acd 系统排队的功能拿号 return acdSystem.addClient(this); } @Override public long getBusinessTime() { // TODO Auto-generated method stub return businessTime; } @Override public BusinessType getBusinessType() { // TODO Auto-generated method stub return businessType; } @Override public long getClientNo() { // TODO Auto-generated method stub return clientNo; } }
ICBCACDSystem
package cn.itcast.project.bank; import java.util.LinkedList; /** * @class: ICBCACDSystem * @package: cn.itcast.project.bank * @description: TODO * @author: vivianZhao * @date: 2013-7-25 下午5:20:03 * @version: 1.0 */ public class ICBCACDSystem implements ACDSystem { private LinkedList<BankClient> generalQueue; private LinkedList<BankClient> fastQueue; private LinkedList<BankClient> vipQueue; public ICBCACDSystem() { super(); generalQueue = new LinkedList<BankClient>(); fastQueue = new LinkedList<BankClient>(); vipQueue = new LinkedList<BankClient>(); } @Override public int addClient(BankClient bankClient) { // TODO Auto-generated method stub // 根据客户类型,把拿号的客户添加到业务类型对应的队列,返回改队列的长度 switch (bankClient.getBusinessType()) { case General: generalQueue.add(bankClient); return generalQueue.size(); case Fast: fastQueue.add(bankClient); return fastQueue.size(); case Vip: vipQueue.add(bankClient); return vipQueue.size(); } return 0; } @Override public synchronized BankClient removeClient(BankWindow bankWindow) { // TODO Auto-generated method stub // 根据窗口的类型从队列中取出相应的客户,如果 fast vip 队列没有客户,那么可以从 general 队列中取一 // 个客户 switch (bankWindow.getBusinessType()) { case General: return generalQueue.pollFirst(); case Fast: if(fastQueue.size() == 0){ return generalQueue.pollFirst(); } return fastQueue.pollFirst(); case Vip: if(vipQueue.size() == 0){ return generalQueue.pollFirst(); } return vipQueue.pollFirst(); } return null; } }