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

来源:互联网 发布:变形金刚5豆瓣知乎 编辑:程序博客网 时间:2024/06/09 18:22

银行业务调度系统的业务需求为:

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

 

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

 

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

 

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

 

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

 

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

 

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

 

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

 

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

 

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

一、    分析

这个系统是要实现客户到银行办理业务的过程,那么我们想一下这个过程:

一个客户要到银行办理业务,就要先到取号机上取对应的号码(普通、快速、vip),然后到相应的窗口办理业务。

这段话中显现出来的对象有:客户(以String代替)、取号机、窗口。

这段话中隐含的对象有:取号机控制器

1、取号机:

       一个客户到银行办理业务,它取号越早,则越先办理它的业务,那么我们可知取号机内部封装了一个队列集合,此处我们使用的为ArrayList集合。一个客户取到号码就相当于此客户添加入集合,此客户办理完业务就相当于此客户从集合中删除,那么我们可知取号机中有两个方法:一个是将元素添加入集合末尾,一个是将集合中首元素从集合中删除。

 

2、取号机控制器

       银行中有三种取号机:普通取号机、快速取号机、vip取号机,客户从相应的取号机中取得号码,即将此客户存入相应的集合中,并且相应类型的取号机的集合只允许存在一个,所以这三种取号机都只允许存在一个对象,那么我们就是通过取号机控制器实现三种取号机的单例,并且因此取号机控制器也为单例模式来实现的。也就是说:取号机控制器中创建了三个取号机对象。我们可以通过相应方法,获取相应的取号机对象。

取号机控制器中有三个方法返回相应的取号机,多次调用的同一个方法,返回的为同一个取号机。

 

3、窗口:

       银行中有三种窗口,所以窗口类中有一个变量,用来标记当前窗口的类型。窗口对外提供服务是独立存在的,所以单独创建一个线程用来启动窗口服务。而窗口的类型不同它启动的服务不同,所以我们要识别窗口的类型,启动相应的服务。而普通、快速、vip这三种不同的服务,又被定义为三个不同的方法。

 

这样银行调度系统中所要实现的重要的三个主类已经分析完了,接下来我们就要实现它。

二、       实现过程

1、实现取号器

我们已知,取号器中封装了一个ArrayList集合用来将客户取出的号码存入此集合中,那么我们如何得知客户取出的号码为多少,那我们就需要在取号器中定义一个int型变量,记录最后取出号码。取号器的代码为:

public class NumberManager {

//用来标记最后一个号码

       private int lastNumber = 0;

       private List queueNumbers = new ArrayList();

       //当客户取出一个号码,就将此号码存入集合中去,并返回上一个号码,为了防止多线程调用出现错误,此方法用synchronized关键字修饰

       public synchronized Integer generateNewNumber(){

               queueNumbers.add(++lastNumber);

               return lastNumber;

       }

       //如果集合中有元素,就删除集合中角标为0的元素,并返回此元素,如果集合中没有元素,返回null,此方法用synchronized关键字修饰

       public synchronized Integer fetchNumber(){

              if(queueNumbers.size()>0){

                     return (Integer)queueNumbers.remove(0);

              }else{

                      return null;

              }

       }

}

2、实现取号控制器

        此类用单例模式实现,有三个相应方法将vip、快速、普通三种不同的窗口对象返回,多次调用同一方法,返回的为同一对象。此类的实现方式为:

public class NumberMachine {

              //实现单例创建此类对象

               private NumberMachine(){}

               private static NumberMachine instance = new NumberMachine();

              public static NumberMachine getInstance(){

                     return instance;

               }

              //创建私有的普通取号器对象

               private NumberManager commonManager = new NumberManager();

//创建私有的快速取号器对象

               private NumberManager expressManager = new NumberManager();

//创建私有的vip取号器对象

               private NumberManager vipManager = new NumberManager();

               //将相应的取号器对象通过相应的方法返回出去

               public NumberManager getCommonManager() {

                     return commonManager;

               }

               public NumberManager getExpressManager() {

                      return expressManager;

               }

               public NumberManager getVipManager() {

                      return vipManager;

               }

}

3、窗口

        窗口中应该有一个标记,用来标记当前窗口的类型此处我们将此标记定义为枚举:

               public enum CustomerType {

                      COMMON,EXPRESS,VIP;

}

客户办理业务的时间有最大值、最小值,不同类型客户来银行的比例也不同,我们也将此定义为一个类,用来记录常量数据。

public class Constants {

                      public static int MAX_SERVICE_TIME = 10000;

                      public static int MIN_SERVICE_TIME = 1000;     

                      public static int COMMON_CUSTOMER_INTERVAL_TIME = 1;

}

至此窗口类的内部已经明晰为:

public class ServiceWindow {

       //用来标记窗口类型

               private CustomerType type = CustomerType.COMMON;

               //用来获取窗口类型

              public CustomerType getType() {

                      return type;

               }

               //用来改变窗口类型

               public void setType(CustomerType type) {

                      this.type = type;

               }

               //新建一个线程用来启动该窗口,即该窗口开始服务了

               public void start(){

                      Executors.newSingleThreadExecutor().execute(

                             new Runnable(){

                                    public void run(){

                                           //true表示该窗口一旦启动,就一直处于服务状态

                                           while(true){

                                                  //针对相应的窗口类型,启动相应的服务

                                                  switch(type){

                                                         case COMMON:

                                                                commonService();

                                                                break;

                                                         case EXPRESS:

                                                                expressService();

                                                                break;

                                                         case VIP:

                                                                vipService();

                                                                break;

                                                  }

                                           }

                                    }

                             }

                     );

              }

               //普通窗口服务过程实现

              private void commonService(){

                            //获取取号机控制器对象

                      NumberMachine  qhjkzq =NumberMachine.getInstance();

                      //通过取号机控制器对象获取相应的取号机对象

                      NumberManager  qhj=qhjkzq.getExpressManager()

                      //获取取号机中集合下标为0的客户号码。

                      Integer serviceNumber =qhj.fetchNumber();      

                      //如果集合非空,即有客户在等待服务,则执行 

                     if(serviceNumber != null ){

                            //获取服务时间

                             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("完成客户服务,总共耗时" + serviceTime/1000 + "");         

               }else{

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

                      try {

                             Thread.sleep(1000);

                      } catch (InterruptedException e) {

                             e.printStackTrace();

                      }                         

               }

       }

       //快速窗口服务过程实现(过程类似)

       private void expressService(){

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

               If(serviceNumber != null)

{

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

}

else

{

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

                      //快速窗体服务普通客户

                      commonService();

}

       }

       //vip窗口服务过程(过程类似)

       private void vipService(){

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

               If(serviceNumber != null)

{

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

}

else

{

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

                      //vip窗体服务普通客户

                      commonService();

}

}

       这样银行调度系统的三个主类已经设计好了,我们只要创建一个类在Main方法中存入客户并调用它们就好了。

 

4MainClass

       main方法中创建相应的服务窗口并启动,另在main方法中启动三个线程,用来向三个相应的取号器中存入客户。

public class MainClass {

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

                                   public void run(){

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

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

                                   }

                            },

                            0,

                            Constants.COMMON_CUSTOMER_INTERVAL_TIME,

                            TimeUnit.SECONDS);

             

              //每隔2秒,来一个快速客户拿号

              Executors.newScheduledThreadPool(1).scheduleAtFixedRate(

                            new Runnable(){

                                   public void run(){

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

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

                                   }

                            },

                            0,

                            Constants.COMMON_CUSTOMER_INTERVAL_TIME * 2,

                            TimeUnit.SECONDS);

             

              //每隔6秒,来VIP客户拿号

              Executors.newScheduledThreadPool(1).scheduleAtFixedRate(

                            new Runnable(){

                                   public void run(){

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

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

                                   }

                            },

                            0,

                            Constants.COMMON_CUSTOMER_INTERVAL_TIME * 6,

                            TimeUnit.SECONDS);

       }

}

       总算写完了,蚊子好多咬死我了。

 

 

原创粉丝点击