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

来源:互联网 发布:java软件开发过程 编辑:程序博客网 时间:2024/06/10 11:31

java高新_银行调度系统

需求:


银行业务调度系统

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

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

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

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

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

客户办理业务所需时间有最大值和最小值,在该范围内随机设定每个VIP客户以及普通客户办理业务所

需的时间,快速客户办理业务所需时间为最小值(提示:办理业务的过程可通过线程Sleep的方式模拟)。

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

当VIP(6号)窗口和快速业务(5号)窗口没有客户等待办理业务的时候,这两个窗口可以处理普通

客户的业务,而一旦有对应的客户等待办理业务的时候,则优先处理对应客户的业务。

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

不要求实现GUI,只考虑系统逻辑实现,可通过Log方式展现程序运行结果。

 


面向对象的分析与设计:

有三种对应类型的客户:VIP客户,普通客户,快速客户 ,异步随机生成各种类型
的客户,各类型客户在其对应窗口按顺序依次办理业务 。
首先,经常在银行办理业务的人更有利于理解本系统,
由于有三类客户,每类客户的号码编排都是完全独立的,所以,我想到本系
统一共要产生三个号码管理器对象,各自管理一类用户的排队号码。这三个号码管
理器对象统一由一个号码机器进行管理,这个号码机器在整个系统中始终只能有一个,所以,它要被设计成单例。
各类型客户在其对应窗口按顺序依次办理业务 ,准确地说,应该是窗口依次叫
号。
各个窗口怎么知道该叫哪一个号了呢?它一定是问的相应的号码管理器,即服务
窗口每次找号码管理器获取当前要被服务的号码。

 

 本项目知识点有:
  1.内部类:覆盖Runnable接口的run方法
  2.线程池:Executors工具类
  3.多线程.
  4.同步函数.
  4.枚举.
  5.单例设计模式

     

//-----------------------------------------------------------------------------
思路:
1、面向对象分析:
 对象:客户、号码管理器、取号器、窗口
2、对象分析:
客户:三种,VIP客户、普通客户、快速客户,异步随机产生
取号器:产生客户的号码,等效于随机生成客户
号码管理器:生成三个叫号器,分别管理三类客户,统一管理,设计成单例
服务窗口:窗口办理业务,内部有叫号的功能,通过获取号码机器的号。
  启动线程,循环调用三个不同的方法,三个方法分别服务三类客户

 

 

NumberManager类
定义一个用于存储上一个客户号码的成员变量和用于存储所有等待服务的客户号码的队列集合。

定义一个产生新号码的方法和获取马上要为之服务的号码的方法,这两个方法被不

同的线程操作了相同的数据,所以,要进行同步

package com.isoftstone.interivew.traffic;import java.util.ArrayList;import java.util.List;public class NumberManager {  //建立集合用于储存号码,尽量面向接口编程 private List<Integer> queueNumber = new ArrayList<Integer>();  //建立变量号码 private int lastNumber = 1;  //往集合里面存储号码.并让号码自增 public synchronized int generateNewNumber(){  queueNumber.add(lastNumber);  return lastNumber++; } //取出号码.删除集合中的0角标元素,返回是集合Integer public synchronized Integer fetchNumber(){  if(queueNumber.size()>0){   return (Integer)queueNumber.remove(0);  }else{   return null;  } }}


 

 

NumberMachine类

定义三个成员变量分别指向三个NumberManager对象,分别表示普通、快速和VIP客户的号码

管理器,定义三个对应的方法来返回这三个NumberManager对象。

将NumberMachine类设计成单例。

package com.isoftstone.interivew.traffic;public class NumberMachine {  //建立三个服务.普通,快速,ivp.是私有的. private NumberManager commonManager = new NumberManager(); private NumberManager expressManager = new NumberManager(); private NumberManager vipManager = new NumberManager();  //通过get方法获取/. public NumberManager getCommonManager() {  return commonManager; } public NumberManager getExpressManager() {  return expressManager; } public NumberManager getVipManager() {  return vipManager; }  //将类设成单利 private NumberMachine(){}; public static NumberMachine instance = new NumberMachine();  public static NumberMachine newInstance(){  return instance; }}


 

 

 


CustomerType枚举类

系统中有三种类型的客户,所以用定义一个枚举类,其中定义三个成员分别表示三种类型的客户。

重写toString方法,返回类型的中文名称。这是在后面编码时重构出来的,刚开始不用考虑。

package com.isoftstone.interivew.traffic;

//枚举public enum CostomerType { COMMON,EXPRESS,VIP; //覆盖toString方法 public String toString(){  String name = null;  switch (this) {  case COMMON:   name = "普通";   break;  case EXPRESS:   name = "快速";   break;  case VIP:   name =name();   break;  }  return name; }} 


 

ServiceWindow类

定义一个start方法,内部启动一个线程,根据服务窗口的类别分别循环调用三个不同的方法。

定义三个方法分别对三种客户进行服务,为了观察运行效果,应详细打印出其中的细节信息。

package com.isoftstone.interivew.traffic;import java.util.Random;import java.util.concurrent.Executors;import com.sun.org.apache.xalan.internal.templates.Constants;public class ServiceWindow {  //枚举.三个属性,普通快速和vip,用于判断,可以通过set方法设置 private CostomerType type = CostomerType.COMMON;  //定义窗口.默认是1,可以通过set方法设置 private int number = 1;  //建立方法 public void start(){    //使用线程池.单线程池,覆盖run方法创建内部类  Executors.newSingleThreadExecutor().execute(new Runnable(){   public void run(){    //开始无限循环    while(true){          //switch选择是否是哪个客户     switch(type){     case COMMON:      commonService();     case EXPRESS:      expressService();     case VIP:      vipService();     }    }   }      //普通客户.抽取成方法   private void commonService() {        String windowName = "第" + number + "号" + type + "窗口";     System.out.println(windowName+ "开始获取普通任务");        //如果是普通客户的话.就在集合中删除号码.    Integer serviceNumber= NumberMachine.instance.getCommonManager().fetchNumber();        //如果集合中有号码的话.就打印xx开始为xx(刚才在集合删除的号码)号码服务    if(serviceNumber != null){     System.out.println(windowName+"开始为"+serviceNumber+"号普通客户服务");          //获取普通客户办理也业务的时间.     int maxRandom = Constant.MAX_SERVICE_TIME - Constant.MIN_SERVICE_TIME;                 int serviceTime = new Random().nextInt(maxRandom)+1 + Constant.MIN_SERVICE_TIME;           try {      //办理业务的时间      Thread.sleep(serviceTime);     } catch (InterruptedException e) {      e.printStackTrace();     }     //完成后,打印xxx完成为第xxx号普通客户服务,总共耗时xxx秒"     System.out.println(windowName + "完成为第" + serviceNumber + "号普通客户服务,总共耗时" + serviceTime/1000 + "秒");         }else{     //如果集合中等于空空的话.就证明没有客户来,开始等待一秒     System.out.println(windowName + "没有取到普通任务,正在空闲一秒");       try {      Thread.sleep(1000);     } catch (InterruptedException e) {      e.printStackTrace();     }        }   }   private void expressService() {    String windowName = "第" + number + "号" + "快速" + "窗口";     System.out.println(windowName+ "开始获取任务");    Integer serviceNumber= NumberMachine.instance.getExpressManager().fetchNumber();        if(serviceNumber != null){     System.out.println(windowName+"开始为"+serviceNumber+"号快速客户服务");          int maxRandom = Constant.MAX_SERVICE_TIME - Constant.MIN_SERVICE_TIME;                 int serviceTime = new Random().nextInt(maxRandom)+1 + Constant.MIN_SERVICE_TIME;        try {      Thread.sleep(serviceTime);     } catch (InterruptedException e) {      e.printStackTrace();     }     System.out.println(windowName + "完成为第" + serviceNumber + "号快速客户服务,总共耗时" + serviceTime/1000 + "秒");         }else{     System.out.println(windowName + "没有取到"+type+"任务,正在空闲一秒");       try {      Thread.sleep(1000);     } catch (InterruptedException e) {      e.printStackTrace();     }        }   }   private void vipService() {    String windowName = "第" + number + "号" + type + "窗口";     System.out.println(windowName+ "开始获取任务");    Integer serviceNumber= NumberMachine.instance.getVipManager().fetchNumber();        if(serviceNumber != null){     System.out.println(windowName+"开始为"+serviceNumber+"号vip客户服务");          int maxRandom = Constant.MAX_SERVICE_TIME - Constant.MIN_SERVICE_TIME;                 int serviceTime = new Random().nextInt(maxRandom)+1 + Constant.MIN_SERVICE_TIME;        try {      Thread.sleep(serviceTime);     } catch (InterruptedException e) {      e.printStackTrace();     }     System.out.println(windowName + "完成为第" + serviceNumber + "号vip客户服务,总共耗时" + serviceTime/1000 + "秒");         }else{     System.out.println(windowName + "没有取到VIP任务!");         commonService();       }   }  }); }  //设置客户和设置窗口号的方法. public void setType(CostomerType type) {  this.type = type; } public void setNumber(int number) {  this.number = number; }}



Constants类

定义三个常量:
MAX_SERVICE_TIME、
MIN_SERVICE_TIME、
COMMON_CUSTOMER_INTERVAL_TIME

package com.isoftstone.interivew.traffic;//定义的秒数类public class Constant { 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;} MainClass类用for循环创建出4个普通窗口,再创建出1个快速窗口和一个VIP窗口。接着再创建三个定时器,分别定时去创建新的普通客户号码、新的快速客户号码、新的VIP客户号码。package com.isoftstone.interivew.traffic;import java.util.concurrent.Executors;import java.util.concurrent.TimeUnit; public class MainClass { /**  * @param args  */ public static void main(String[] args) {  // TODO Auto-generated method stub    //建立四个窗口  for(int i=1 ; i<5 ; i++){   //创建窗口对象   ServiceWindow conmonWindow = new ServiceWindow();   //设置窗口号   conmonWindow.setNumber(i);   //让普通窗口跑起来   conmonWindow.start();  }  //建立vip窗口对象.并设置窗口号.和窗口  ServiceWindow VIPWindow = new ServiceWindow();  VIPWindow.setType(CostomerType.VIP);  VIPWindow.setNumber(6);  VIPWindow.start();    //建立快速窗口.并设置窗口号.和窗口  ServiceWindow expressWindow = new ServiceWindow();  expressWindow.setType(CostomerType.EXPRESS);  expressWindow.setNumber(5);  expressWindow.start();    //普通客户拿号..建立线程池.定时炸弹.  Executors.newScheduledThreadPool(1).scheduleAtFixedRate(    new Runnable(){     public void run(){      //往集合中添加号码      Integer serviceNumber = NumberMachine.newInstance().getCommonManager().generateNewNumber();      /**       * 采用logger方式,无法看到直观的运行效果,因为logger.log方法内部并不是直接把内容打印出出来,       * 而是交给内部的一个线程去处理,所以,打印出来的结果在时间顺序上看起来很混乱。       */      //logger.info("第" + serviceNumber + "号普通客户正在等待服务!");      System.out.println("第" + serviceNumber + "号普通客户正在等待服务!");           }    },    0,//等待0秒.然后一秒产生一个号码    Constant.COMMON_CUSTOMER_INTERVAL_TIME,     TimeUnit.SECONDS);    //快速客户拿号  Executors.newScheduledThreadPool(1).scheduleAtFixedRate(    new Runnable(){     public void run(){      Integer serviceNumber = NumberMachine.newInstance().getExpressManager().generateNewNumber();      System.out.println("第" + serviceNumber + "号快速客户正在等待服务!");     }    },    0,    //两秒钟炸一次    Constant.COMMON_CUSTOMER_INTERVAL_TIME * 2,     TimeUnit.SECONDS);    //VIP客户拿号  Executors.newScheduledThreadPool(1).scheduleAtFixedRate(    new Runnable(){     public void run(){      Integer serviceNumber = NumberMachine.newInstance().getVipManager().generateNewNumber();      System.out.println("第" + serviceNumber + "号VIP客户正在等待服务!");     }    },    0,    //六秒钟炸一次    Constant.COMMON_CUSTOMER_INTERVAL_TIME * 6,     TimeUnit.SECONDS);  }}



*********************************************************************************