银行调度系统

来源:互联网 发布:800万淘宝卖家 编辑:程序博客网 时间:2024/06/10 15:21

银行业务调度系统的项目需求

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

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

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

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

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

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

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

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

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

1.     面向对象的分析和设计:

a)       有三种对应类型的客户:VIP客户,普通客户,快速客户 ,异步随机生成各种类型的客户,各类型客户在其对应窗口按顺序依次办理业务 。

l        由于有三类客户,每类客户的号码编排都是完全独立的,所以,我想到本系统一共要产生三个号码管理器对象,各自管理一类用户的排队号码。这三个号码管理器对象统一由一个号码机器进行管理,这个号码机器在整个系统中始终只能有一个,所以,它要被设计成单例。

l        各类型客户在其对应窗口按顺序依次办理业务,准确地说,应该是窗口依次叫号。

2.    

3.    代码分析

a)       NumberManager类

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

l        定义一个产生新号码的方法和获取马上要为之服务的号码的方法,这两个方法被不同的线程操作了相同的数据,所以,要进行同步

import java.util.ArrayList;

import java.util.List;

 

public class NumberManager {

     private int lastNumber = 0;

     private List queueNumbers = newArrayList();

    

     //生成排队票

     public synchronized Integer generateNewNumber(){

         queueNumbers.add(++lastNumber);

         returnlastNumber;

     }

    

     //取票的方法

     public synchronized Integer fetchNumber(){

         if(queueNumbers.size()>0){

              return (Integer)queueNumbers.remove(0);

         }else{

              return null;

         }

     }

}

b)       NumberMachine类

l        定义三个成员变量分别指向三个NumberManager对象,分别表示普通、快速和VIP客户的号码管理器,定义三个对应的方法来返回这三个NumberManager对象。

l        将NumberMachine类设计成单例。

public class NumberMachine {

    

     private NumberMachine(){}

     private static NumberMachine instance =new NumberMachine();

     public static NumberMachine getInstance(){

         returninstance//返回本类的实例化对象

     }

    

     private NumberManagercommonManager =new NumberManager();//创建普通客户的实例化对象

     private NumberManagerexpressManager =new NumberManager();//创建快速客户的实例化对象

     private NumberManagervipManager =new NumberManager();//创建VIP客户的实例化对象

     public NumberManager getCommonManager() {

         returncommonManager;//返回普通客户的实例化对象

     }

     public NumberManager getExpressManager() {

         returnexpressManager;//返回快速客户的实例化对象

     }

     public NumberManager getVipManager() {

         returnvipManager;//返回VIP客户的实例化对象

     }}

c)        CustomerType枚举类

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

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

public enum CustomerType{

      COMMON,EXPRESS,VIP;

      public String toString(){

           String name = null;

           switch(this){

           caseCOMMON:

                 name = "普通";

                 break;

           caseEXPRESS:

                 name = "快速";

                 break;

           caseVIP:

                 name = name();

                 break;

           }

           return name;

      }}

d)         ServiceWindow类

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

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

import java.util.Random;

import java.util.concurrent.Executors;

import java.util.logging.Logger;

 

/**

 * 没有把VIP窗口和快速窗口做成子类,是因为实际业务中的普通窗口可以随时被设置为VIP窗口和快速窗口。

 * */

public class ServiceWindow {

      private static Logger logger = Logger.getLogger("cn.itcast.bankqueue");

      private CustomerTypetype = CustomerType.COMMON;

      private int number = 1;

 

      public CustomerType getType() {

           returntype;

      }

 

      public void setType(CustomerType type) {

           this.type = type;

      }

     

      public void setNumber(int number){

           this.number = number;

      }

     

      public void start(){

           Executors.newSingleThreadExecutor().execute(

                      new Runnable(){

                            publicvoid run(){

                                  //下面这种写法的运行效率低,最好是把while放在case下面

                                  while(true){

                                       switch(type){

                                             caseCOMMON:

                                                  commonService();

                                                  break;

                                             caseEXPRESS:

                                                  expressService();

                                                  break;

                                             caseVIP:

                                                  vipService();

                                                  break;

                                       }

                                  }

                            }

                      }

           );

      }

     

      private void commonService(){

           String windowName = "" +number +"" +type +"窗口";          

           System.out.println(windowName +"开始获取普通任务!");

           Integer serviceNumber = NumberMachine.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) {

                      e.printStackTrace();

                 }    

                 System.out.println(windowName +"完成为第" + serviceNumber +"号普通客户服务,总共耗时" + serviceTime/1000 +"");     

           }else{

                 System.out.println(windowName +"没有取到普通任务,正在空闲一秒");         

                 try {

                      Thread.sleep(1000);

                 } catch (InterruptedException e) {

                      e.printStackTrace();

                 }                    

           }

      }

     

      private void expressService(){

           Integer serviceNumber = NumberMachine.getInstance().getExpressManager().fetchNumber();

           String windowName = "" +number +"" +type +"窗口";    

           System.out.println(windowName +"开始获取快速任务!");         

           if(serviceNumber !=null){

                 System.out.println(windowName +"开始为第" + serviceNumber +"号快速客户服务");            

                 int serviceTime = Constants.MIN_SERVICE_TIME;

                 try {

                      Thread.sleep(serviceTime);

                 } catch (InterruptedException e) {

                      e.printStackTrace();

                 }         

                 System.out.println(windowName +"完成为第" + serviceNumber +"号快速客户服务,总共耗时" + serviceTime/1000 +"");     

           }else{

                 System.out.println(windowName +"没有取到快速任务!");                    

                 commonService();

           }

      }

     

      private void vipService(){

 

           Integer serviceNumber = NumberMachine.getInstance().getVipManager().fetchNumber();

           String windowName = "" +number +"" +type +"窗口";    

           System.out.println(windowName +"开始获取VIP任务!");               

           if(serviceNumber !=null){

                 System.out.println(windowName +"开始为第" + serviceNumber +"VIP客户服务");            

                 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) {

                      e.printStackTrace();

                 }         

                 System.out.println(windowName +"完成为第" + serviceNumber +"VIP客户服务,总共耗时" + serviceTime/1000 +"");      

           }else{

                 System.out.println(windowName +"没有取到VIP任务!");                    

                 commonService();

           }     }

e)        MainClass类

l        用for循环创建出4个普通窗口,再创建出1个快速窗口和一个VIP窗口。

l        接着再创建三个定时器,分别定时去创建新的普通客户号码、新的快速客户号码、新的VIP客户号码。

import java.util.concurrent.Executors;

import java.util.concurrent.TimeUnit;

import java.util.logging.Logger;

 

public class MainClass {

     

      private static Logger logger = Logger.getLogger("cn.itcast.bankqueue");

     

 

      public static void main(String[] args) {

           //产生4个普通窗口

           for(int i=1;i<5;i++){

                 ServiceWindow window =  new ServiceWindow();

                 window.setNumber(i);

                 window.start();

           }

     

           //产生1个快速窗口

           ServiceWindow expressWindow =  new ServiceWindow();

           expressWindow.setType(CustomerType.EXPRESS);

           expressWindow.start();

          

           //产生1VIP窗口      

           ServiceWindow vipWindow = new ServiceWindow();

           vipWindow.setType(CustomerType.VIP);

           vipWindow.start();         

          

           //普通客户拿号

           Executors.newScheduledThreadPool(1).scheduleAtFixedRate(

                      new Runnable(){

                            publicvoid run(){

                                  Integer serviceNumber =NumberMachine.getInstance().getCommonManager().generateNewNumber();

                                  /**

                                   * 采用logger方式,无法看到直观的运行效果,因为logger.log方法内部并不是直接把内容打印出出来,

                                   * 而是交给内部的一个线程去处理,所以,打印出来的结果在时间顺序上看起来很混乱。

                                   */

                                  //logger.info("" + serviceNumber + "号普通客户正在等待服务!");

                                  System.out.println("" + serviceNumber +"号普通客户正在等待服务!");                                

                            }

                      },

                      0,

                      Constants.COMMON_CUSTOMER_INTERVAL_TIME,

                      TimeUnit.SECONDS);

          

           //快速客户拿号

           Executors.newScheduledThreadPool(1).scheduleAtFixedRate(

                      new Runnable(){

                            publicvoid run(){

                                  Integer serviceNumber =NumberMachine.getInstance().getExpressManager().generateNewNumber();

                                  System.out.println("" + serviceNumber +"号快速客户正在等待服务!");

                            }

                      },

                      0,

                      Constants.COMMON_CUSTOMER_INTERVAL_TIME * 2,

                      TimeUnit.SECONDS);

          

           //VIP客户拿号

           Executors.newScheduledThreadPool(1).scheduleAtFixedRate(

                      new Runnable(){

                            publicvoid run(){

                                  Integer serviceNumber =NumberMachine.getInstance().getVipManager().generateNewNumber();

                                  System.out.println("" + serviceNumber +"VIP客户正在等待服务!");

                            }

                      },

                      0,

                      Constants.COMMON_CUSTOMER_INTERVAL_TIME * 6,

                      TimeUnit.SECONDS);

      }

}

f)        Constants类

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

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;    }

4.    面向对象设计面对一些复杂的问题起到了简单化的作用,要熟练的掌握面向对象和枚举单例设计,还有就是涉及到了线程池的技术,也要了解其作用。


原创粉丝点击