银行业务调度系统

 

1.需求:

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

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

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

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

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

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


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

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

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

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

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

2.示意图: (- -!原创)

银行业务调度系统

3.源代码:

NumberManager:

package com.itheima.bankingsystem;

import java.util.ArrayList;
import java.util.List;

/*号码管理器负责号码的生成和获取(返回)*/
public class NumberManager {
  private int number=1;//每个号码管理器生成号码都从1开始
  private List<Integer> storeNumbers =new ArrayList<Integer>();
  public synchronized int generateNumber(){//由客户去取生成的号码
      storeNumbers.add(number);
       return number++;
  }
  public synchronized Integer fetchNumber(){//由服务窗口获取号码
      if(storeNumbers.size()!=0)
          return storeNumbers.remove(0);//返回集合中第一个元素,队头元素保证FIFO
      else
         return null;//集合中可能没有元素
  }
 /*窗口的取动作与客户的放动作在操作同一个集合,使用同步,这里的锁为它们对应的 同一个号码管理器实例*/ 
}

NumberMachine:

package com.itheima.bankingsystem;
/*
 负责统一管理三个号码管理器,NumberMachine在程序运行期间只需要一个实例
设计成单例.
 */
public class NumberMachine {
   private NumberManager commonManager=new NumberManager();
   private NumberManager vipManager=new NumberManager();
   private NumberManager expressManager=new NumberManager();
   public NumberManager getCommonManager(){//由于该类只有一个实例,因此成员commonManager的值不变
       return commonManager;               //也就是说多次调用getCommonManager()获取到的是同一个
   }                                       //NumberManager实例,下面同理
   public NumberManager getVIPManager(){
       return vipManager;
   }
   public NumberManager getExpressManager(){
       return expressManager;
   }
   
   /*NumberMachine在程序运行时在内存限制只有一个实例*/
   private NumberMachine(){}
   private static final NumberMachine ref=new NumberMachine();
   public static NumberMachine getInstance(){
       return ref;
   }
}

两个枚举:windowType和TimeConstant

package com.itheima.bankingsystem;

public enum WindowType {
   COMMON,VIP,EXPRESS;
   @Override
   public String toString(){
       switch(this){
           case COMMON: return "普通";
           case VIP: return "VIP";
           case EXPRESS: return "快速";
           default: return null;
       }
   }
}
package com.itheima.bankingsystem;

//设置客户办理业务所需时间的最大值和最小值
public class TimeConstant {
    public static final int MIN_SERVICE_TIME=2;//服务最小时间
    public static final int MAX_SERVICE_TIME=10;//服务最大时间
    
    public static final int COMMON_CUSTOMER_INTERVAL_TIME=1;//每个普通用户来的时间间隔1秒
    public static final int VIP_CUSTOMER_INTERVAL_TIME=6;//每个VIP用户来的时间间隔6秒
    public static final int EXPRESS_CUSTOMER_INTERVAL_TIME=2;//每个快速用户来的时间间隔2秒
}

ServiceWindow:

package com.itheima.bankingsystem;

import java.util.Random;
import java.util.concurrent.Executors;

public class ServiceWindow {
  private WindowType windowType=WindowType.COMMON;//把三种窗口类型定义成枚举
  private int windowID=1;//窗口的编号 
  public void setType(WindowType windowType) {//通过set方法设置窗口类型和窗口编号进行设置
        this.windowType = windowType;         //而没有通过构造方法在创建对象时传入
  }                                           //这样做可以修改已创建服务窗口对象的ID和type
  public void setWindowID(int windowID) {
        this.windowID = windowID;
  }
  public void start(){//相当于启动了NumberMachine,根据服务的不同
                      //获取不同号码管理器,然后在获取号码
     Executors.newSingleThreadExecutor().execute(
        new Runnable(){
             @Override
                public void run(){      
                 while(true){//不断的获取服务窗口不断获取服务(fetchNumber)
                     switch(windowType){
                         case COMMON:commonService();break;
                         case VIP:vipService();break;
                         case EXPRESS:expressService();
                            
                     }
                }            
            }     
        }     
      ); 
   }
  public void commonService(){
      String windowName=windowID+"号"+windowType+"窗口";               
      Integer serviceNumber=NumberMachine.getInstance().getCommonManager().fetchNumber();//服务窗口开始拿号,为该号客户提供服务  
       System.out.println(windowName+"正在获取任务");         
      if (serviceNumber!=null){
           System.out.println(windowName+"正在为第"+serviceNumber+"个"+"普通客户服务"); 
          
           int minServiceTime=TimeConstant.MIN_SERVICE_TIME;
          int maxServiceTime=TimeConstant.MAX_SERVICE_TIME;
          int serviceTime=new Random().nextInt(maxServiceTime-minServiceTime)+1+minServiceTime;//随机生成2~10秒
          try {
                Thread.sleep(serviceTime*1000);
             } catch (InterruptedException e) {
        
                e.printStackTrace(); 
             }
          
   
          System.out.println(windowName+"为第"
                        +serviceNumber+"个"+"普通客户服务了"
//这里没用windowType而固定使用"普通"字符串
                        +serviceTime+"s");    //这是因为例如:在vipService方法中没有vip服务时,会调用commonService
      }                                     //此时this.windowType=VIP,会错误打印VIP客户服务
      else{
          System.out.println(windowName+"窗口没有获取到"+"普通任务休息1秒钟再去获取");
          try {
                Thread.sleep(1000);//服务窗口休息1秒后再去拿号
           } catch (InterruptedException e) {
                // TODO 自动生成的 catch 块
                e.printStackTrace();
           }
      }
  }
  public void vipService(){
        String windowName=windowID+"号"+windowType+"窗口";   
        Integer serviceNumber=NumberMachine.getInstance().getVIPManager().fetchNumber();//服务窗口开始拿号,为该号客户提供服务  
        System.out.println(windowName+"正在获取任务");   
         
          if (serviceNumber!=null){//取到number,开始服务
              System.out.println(windowName+"正在为第"+serviceNumber+"个"+windowType+"客户服务"); 
               int minServiceTime=TimeConstant.MIN_SERVICE_TIME;
              int maxServiceTime=TimeConstant.MAX_SERVICE_TIME;
              int serviceTime=new Random().nextInt(maxServiceTime-minServiceTime)+1+minServiceTime;//随机生成2~10秒
              try {
                    Thread.sleep(serviceTime*1000);
                 } catch (InterruptedException e) {
                    // TODO 自动生成的 catch 块
                    e.printStackTrace();
                 }
              
          
              System.out.println(windowName+"为第"
                      +serviceNumber+"个"+windowType+"客户服务了" 
                          +serviceTime+"s");
          }    
          else{
              System.out.println(windowName+"窗口没有获取到"+windowType+"任务");
              commonService();//VIP窗口没有获取到VIP任务,获取普通任务去服务,直接调用了 commonService(),去普通任务集合去取
          }
  }
  public void expressService(){
         String windowName=windowID+"号"+windowType+"窗口";   
         Integer serviceNumber=NumberMachine.getInstance().getExpressManager().fetchNumber();//服务窗口开始拿号,为该号客户提供服务  
         System.out.println(windowName+"正在获取任务");   
          if (serviceNumber!=null){//取到number,开始服务
              System.out.println(windowName+"正在为第"+serviceNumber+"个"+windowType+"客户服务");
            
              
              int serviceTime=TimeConstant.MIN_SERVICE_TIME;
            
              try {
                    Thread.sleep(serviceTime*1000);
                 } catch (InterruptedException e) {
                    // TODO 自动生成的 catch 块
                    e.printStackTrace();
                 }
              
            
              System.out.println(windowName+"为第"
                            +serviceNumber+"个"+windowType+"客户服务了" 
                            +serviceTime+"s");
          }    
          else{
              System.out.println(windowName+"窗口没有获取到"+windowType+"任务");
              commonService();//express窗口没有获取到express任务,获取普通任务去服务,直接调用了 commonService()
          }
   }
}

MainClass:

package com.itheima.bankingsystem;

import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class MainClass {
  public static void main(String[] args){
     /*创建六个窗口对象(,1个VIP窗口,1个快速窗口)*/
      //4个普通窗口
      for(int i=1;i<5;++i){
         ServiceWindow commonWindow=new ServiceWindow();
         commonWindow.setWindowID(i);
         commonWindow.start();//开启服务
      }
      //1个VIP窗口 
      ServiceWindow vipWindow=new ServiceWindow();
      vipWindow.setType(WindowType.VIP);
      vipWindow.setWindowID(6);
      vipWindow.start();
      //1个快速窗口
     ServiceWindow expressWindow=new ServiceWindow();
      expressWindow.setType(WindowType.EXPRESS); 
      expressWindow.setWindowID(5);
      expressWindow.start();
     
      /*
         模拟客户来取 
      VIP客户 :普通客户 :快速客户  =  1 :6 :3
        这个比例通过计时器来完成,假设每隔1秒来一个普通客户,每隔2秒来来一个快速客户.  
      ,每隔六秒来一个VIP客户.
        假设程序运行了12秒,来了12(12/1)个普通客户,6个快速客户(12/2),2个VIP客户(12/6)
       2:12:6=1:6:3;
      */
      Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
              new Runnable(){
                  @Override 
                  public void run(){
                    int number=NumberMachine.getInstance().getCommonManager().generateNumber();
                    System.out.println("第"+number+"号普通客户等待服务");
                  }
              },
              1,
              TimeConstant.COMMON_CUSTOMER_INTERVAL_TIME, 
              TimeUnit.SECONDS);
      Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
              new Runnable(){
                  @Override 
                  public void run(){
                      int number=NumberMachine.getInstance().getVIPManager().generateNumber();
                      System.out.println("第"+number+"号VIP客户等待服务");
                  }
              },
              1,
              TimeConstant.VIP_CUSTOMER_INTERVAL_TIME, 
              TimeUnit.SECONDS);
                       
     Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
              new Runnable(){
                  @Override 
                  public void run(){
                      int number=NumberMachine.getInstance().getExpressManager().generateNumber();
                      System.out.println("第"+number+"号快速客户等待服务");
                  }
              },
              1,
              TimeConstant.EXPRESS_CUSTOMER_INTERVAL_TIME, 
              TimeUnit.SECONDS);
                
  }
}

运行结果

运行结果可以通过输出到文本方式测试.

3.用模板方法设计模式改写ServiceWindow:

package com.itheima.bankingsystem;

import java.util.Random;
import java.util.concurrent.Executors;

public class ServiceWindowNewCode {
  private WindowType windowType=WindowType.COMMON;
  private int windowID=1;//窗口的编号 
  String windowName=windowID+"号"+windowType+"窗口";
  public void setType(WindowType windowType) {
        this.windowType = windowType;         
  }                                          
  public void setWindowID(int windowID) {
        this.windowID = windowID;
  }
  public void start(){
     Executors.newSingleThreadExecutor().execute(
        new Runnable(){
             @Override
                public void run(){      
                 while(true){
                     Service();//默认为:普通窗口
                }            
            }     
        }     
      ); 
   }
 
  public void Service(){
      
      Integer serviceNumber=getServiceNumber();//不同的窗口对象会使用各自复写的getServiceNumber()方法(多态)
       System.out.println(windowName+"正在获取任务");         
      if (serviceNumber!=null){
           System.out.println(windowName+"正在为第"+serviceNumber+"个"+"普通客户服务"); 
   
          long serviceTime=getServiceTime();
          
          try {
                Thread.sleep(serviceTime);
             } catch (InterruptedException e) {
        
                e.printStackTrace(); 
             }
        }                                  
      else
          notTakeTaskNext();
  }
 
  /*不同类型的客户需要从不同的号码管理器获取ServiceNumber*/
  protected int getServiceNumber(){
     return NumberMachine.getInstance().getCommonManager().fetchNumber();
     
  }
  /*VIP和COMMON服务时间在同一个范围内,EXPRESS为最小值*/
  protected long getServiceTime(){
      int minServiceTime=TimeConstant.MIN_SERVICE_TIME;
      int maxServiceTime=TimeConstant.MAX_SERVICE_TIME;
      int serviceTime=new Random().nextInt(maxServiceTime-minServiceTime)+1+minServiceTime;//随机生成2~10秒
      return serviceTime*1000;
  }
  /*打印出哪个窗口正在为那个客户服务*/
  protected void printServiceCustomer(){
      System.out.println(windowName+"正在为第"+getServiceNumber()+"个"+"普通客户服务"); 
  }
  /*打印服务了多长时间*/
  protected void printServiceTime(){
       System.out.println(windowName+"为第"
               +getServiceNumber()+"个"+"普通客户服务了" 
               +getServiceTime()+"s"); 
  }
  /*窗口未取到任务需要干的事*/
  protected void notTakeTaskNext(){
      System.out.println(windowName+"窗口没有获取到"+"普通任务休息1秒钟再去获取");
      try {
            Thread.sleep(1000);//服务窗口休息1秒后再去拿号
       } catch (InterruptedException e) {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
       }
  }
}

VIPServiceWindow

class VIPServiceWindow extends ServiceWindowNewCode{
    private  WindowType windowType=WindowType.VIP;//把三种窗口类型定义成枚举
    protected int getServiceNumber(){//复写
      return NumberMachine.getInstance().getVIPManager().fetchNumber();
             
    }
    protected void printServiceTime(){
           System.out.println(windowName+"为第"
                   +getServiceNumber()+"个"+windowType+"客户服务了" 
                   +getServiceTime()+"s"); 
     }
    protected void notTakeTaskNext(){//复写
         System.out.println(windowName+"窗口没有获取到"+windowType+"任务");
          new ServiceWindowNewCode().Service();//必须通过对象来调用普通窗口服务
    }
}

ExpressServiceWindow

class ExpressServiceWindow extends ServiceWindowNewCode{
    private WindowType windowType=WindowType.EXPRESS;
    protected int getServiceNumber(){//复写
          return NumberMachine.getInstance().getExpressManager().fetchNumber();
                 
    }
    protected long getServiceTime(){
         return TimeConstant.MIN_SERVICE_TIME;
      }
    protected void printServiceTime(){
           System.out.println(windowName+"为第"
                   +getServiceNumber()+"个"+windowType+"客户服务了" 
                   +getServiceTime()+"s"); 
     }
    protected void notTakeTaskNext(){//复写
        System.out.println(windowName+"窗口没有获取到"+windowType+"任务");
         new ServiceWindowNewCode().Service();//必须通过对象来调用普通窗口服务
   }
}
posted @ 2013-08-12 20:58  伊秋  阅读(651)  评论(0编辑  收藏  举报