------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------
一、需求
模拟实现银行业务调度系统逻辑,具体需求如下:
1、银行内有6个业务窗口,1 - 4号窗口为普通窗口,5号窗口为快速窗口,6号窗口为VIP窗口。
2、有三种对应类型的客户:VIP客户,普通客户,快速客户(办理如交水电费、电话费之类业务的客户)。
3、异步随机生成各种类型的客户,生成各类型用户的概率比例为:
VIP客户 :普通客户 :快速客户 = 1 :6 :3。
4、客户办理业务所需时间有最大值和最小值,在该范围内随机设定每个VIP客户以及普通客户办理业务所需的时间,快速客户办理业务所需时间为最小值(提示:办理业务的过程可通过线程Sleep的方式模拟)。
5、各类型客户在其对应窗口按顺序依次办理业务。
6、 当VIP(6号)窗口和快速业务(5号)窗口没有客户等待办理业务的时候,这两个窗口可以处理普通客户的业务,而一旦有对应的客户等待办理业务的时候,则优先处理对应客户的业务。
7、随机生成客户时间间隔以及业务办理时间最大值和最小值自定,可以设置。
8、不要求实现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.根据变化重构——重构
三、代码实现
号码管理:
- <span style="font-size:14px;">package cn.itcast.interview2;
- import java.util.ArrayList;
- import java.util.List;
- public class NumberManager {
- //定义私有成员变量lastNumber,表示队列中最后一个数
- private int lastNumber = 0;
- //定义list集合queueNumber用于存放号码
- public List<Integer> queueNumber= new ArrayList<Integer>();
- //定义方法generateNewNumber()用于产生号码
- //由于产生号码和获取号码必须保证同步,因此加入同步代码块
- public synchronized Integer generateNewNumber(){
- queueNumber.add(++lastNumber);
- return lastNumber;
- }
- //定义方法fetchNumber()用于获取排列在最初的号码
- //由于产生号码和获取号码必须保证同步,因此加入同步代码块
- public synchronized Integer fetchNumber(){
- if (queueNumber.size()>0){
- return (Integer)queueNumber.remove(0);
- }else{
- return null;
- }
- }
- }</span>
取号机:
- package cn.itcast.interview2;
- public class NumberMechine {
- /*号码机是用于给不同柜台产生号码用的,由于号码机的唯一性,这里考虑使用单例设计模式*/
- //首先,构造函数私有化
- private NumberMechine(){}
- //其次,创建本类对象
- private static NumberMechine instance = new NumberMechine();
- //最后,提供获得实例的方法
- public static NumberMechine getInstance(){
- return instance;
- }
- //定义三个窗口的对象,并提供get方法
- private NumberManager commonManager = new NumberManager();
- private NumberManager expressManager = new NumberManager();
- private NumberManager vipManager = new NumberManager();
- public NumberManager getCommonManager() {
- return commonManager;
- }
- public NumberManager getExpressManager() {
- return expressManager;
- }
- public NumberManager getVipManager() {
- return vipManager;
- }
- }
客户类型类:
- package cn.itcast.interview2;
- public enum CustomerType {
- /*三种顾客类型分别是,普通客户,快速客户,VIP客户*/
- COMMON,
- EXPRESS,
- VIP;
- public String toString(){
- String name = null;
- switch(this){
- case COMMON:
- name = "普通";
- break;
- case EXPRESS:
- name = "快速";
- break;
- case VIP:
- name = "VIP";
- break;
- }
- return name;
- }
- }
常量时间定义:
- package cn.itcast.interview2;
- public class Constants {
- public static int MAX_SERVICE_TIME = 10000; //10秒!
- public static int MIN_SERVICE_TIME = 1000; //1秒!
- /*每个普通窗口服务一个客户的平均时间为5秒,一共有4个这样的窗口,也就是说银行的所有普通窗口合起来
- * 平均1.25秒内可以服务完一个普通客户,再加上快速窗口和VIP窗口也可以服务普通客户,所以,
- * 1秒钟产生一个普通客户比较合理,*/
- public static int COMMON_CUSTOMER_INTERVAL_TIME = 1;
- }
服务窗口:对象理解:一个窗口就是一个对象,所以需要6个这样的对象。
但有三类窗口,即里面要判断三种创建对象的方式。
窗口本身的数据:窗口类型及几号,可变客户号码【窗口的叫号方法(关联取号机器)】,服务时间,等待时间。
- package cn.itcast.interview2;
- import java.util.Random;
- import java.util.concurrent.Executors;
- import java.util.logging.Logger;
- public class ServiceWindow {
- private static Logger logger = Logger.getLogger("cn.itcast.interview2");
- private CustomerType type = CustomerType.COMMON;
- private int number = 1;
- public void setType(CustomerType type){
- this.type = type;
- }
- public CustomerType getType() {
- return type;
- }
- public void setNumber(int number) {
- this.number = number;
- }
- public void start(){
- Executors.newSingleThreadExecutor().execute(
- new Runnable(){
- public void run(){
- while(true){
- switch(type){
- case COMMON:
- commonServer();
- break;
- case EXPRESS:
- expressServer();
- break;
- case VIP:
- vipServer();
- break;
- }
- }
- }
- });
- }
- private void commonServer() {
- String windowName = "第"+number+"号"+type+"窗口";
- System.out.println(windowName+"为您服务,开始获取普通任务!");
- Integer serviceNumber = NumberMechine.getInstance().getCommonManager().fetchNumber();
- if (serviceNumber!=null){
- System.out.println(windowName + "开始为第"+serviceNumber+"号客户服务");
- int maxRandom = Constants.MAX_SERVICE_TIME - Constants.MIN_SERVICE_TIME;
- int serviceTime = new Random().nextInt(maxRandom) + 1 + Constants.MIN_SERVICE_TIME;
- try {
- Thread.sleep(serviceTime);
- } catch (InterruptedException e) {
- // TODO 自动生成的 catch 块
- e.printStackTrace();
- }
- System.out.println(windowName + "完成为第" + serviceNumber + "号普通客户服务,总共耗时" + serviceTime/1000 + "秒");
- }else{
- System.out.println("没有取到普通任务,一秒后重新取任务!");
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- // TODO 自动生成的 catch 块
- e.printStackTrace();
- }
- }
- }
- protected void expressServer() {
- String windowName = "第"+number+"号"+type+"窗口";
- System.out.println(windowName+"为您服务,开始获取快速任务!");
- Integer serviceNumber = NumberMechine.getInstance().getExpressManager().fetchNumber();
- if (serviceNumber!=null){
- System.out.println(windowName + "开始为第"+serviceNumber+"号客户服务");
- int serviceTime =Constants.MIN_SERVICE_TIME;
- try {
- Thread.sleep(serviceTime);
- } catch (InterruptedException e) {
- // TODO 自动生成的 catch 块
- e.printStackTrace();
- }
- System.out.println(windowName + "完成为第" + serviceNumber + "号快速客户服务,总共耗时" + serviceTime/1000 + "秒");
- }else{
- System.out.println("没有取到快速任务,正在尝试获取普通任务!");
- commonServer();
- }
- }
- protected void vipServer() {
- String windowName = "第"+number+"号"+type+"窗口";
- System.out.println(windowName+"为您服务,开始获取VIP任务!");
- Integer serviceNumber = NumberMechine.getInstance().getVipManager().fetchNumber();
- if (serviceNumber!=null){
- System.out.println(windowName + "开始为第"+serviceNumber+"号客户服务");
- int maxRandom = Constants.MAX_SERVICE_TIME - Constants.MIN_SERVICE_TIME;
- int serviceTime = new Random().nextInt(maxRandom) + 1 + Constants.MIN_SERVICE_TIME;
- try {
- Thread.sleep(serviceTime);
- } catch (InterruptedException e) {
- // TODO 自动生成的 catch 块
- e.printStackTrace();
- }
- System.out.println(windowName + "完成为第" + serviceNumber + "号VIP客户服务,总共耗时" + serviceTime/1000 + "秒");
- }else{
- System.out.println("没有取到VIP任务,正在尝试获取普通任务!");
- commonServer();
- }
- }
- }
- package cn.itcast.interview2;
- import java.util.concurrent.Executors;
- import java.util.concurrent.TimeUnit;
- public class MainClass {
- public static void main(String[] args) {
- //产生4个普通窗口
- for (int i = 0; i < 5; i++){
- ServiceWindow window = new ServiceWindow();
- window.setNumber(i);
- window.start();
- }
- //产生一个快速窗口
- ServiceWindow expressWindow = new ServiceWindow();
- expressWindow.setType(CustomerType.EXPRESS);
- expressWindow.start();
- //产生一个vip窗口
- ServiceWindow vipWindow = new ServiceWindow();
- vipWindow.setType(CustomerType.VIP);
- vipWindow.start();
- //普通客户拿号
- Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
- new Runnable(){
- public void run(){
- Integer serviceNumber = NumberMechine.getInstance().getCommonManager().generateNewNumber();
- System.out.println("第" + serviceNumber + "号普通客户正在等待服务!");
- }
- },
- 0,
- Constants.COMMON_CUSTOMER_INTERVAL_TIME,
- TimeUnit.SECONDS
- );
- //快速客户拿号
- Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
- new Runnable(){
- public void run(){
- Integer serviceNumber = NumberMechine.getInstance().getExpressManager().generateNewNumber();
- System.out.println("第" + serviceNumber + "号快速客户正在等待服务!");
- }
- },
- 0,
- Constants.COMMON_CUSTOMER_INTERVAL_TIME*3,
- TimeUnit.SECONDS
- );
- //vip客户拿号
- Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
- new Runnable(){
- public void run(){
- Integer serviceNumber = NumberMechine.getInstance().getVipManager().generateNewNumber();
- System.out.println("第" + serviceNumber + "号vip客户正在等待服务!");
- }
- },
- 0,
- Constants.COMMON_CUSTOMER_INTERVAL_TIME*6,
- TimeUnit.SECONDS
- );
- }
- }