银行调度系统

来源:互联网 发布:天迹淘宝货源小管家 编辑:程序博客网 时间:2024/06/10 10:45


银行调度系统

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

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

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

3.有三种对应类型的客户:VIP客户,普通客户,快速客户

4.异步随机生成各种类型的客户,生成各类型用户的概率比利为:VIP客户:普通客户:快速客户=1:6:3.

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

6.各类型客户在其对应窗口按顺序依次办理业务。当VIP窗口和快速业务窗口没有客户等待办理业务的时候,这两个窗口可以处理普通客户的业务,而一旦有对应的客户等待办理业务的时候,则优先处理对应客户的业务。

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

8.不要求实现GUI,只考虑系统逻辑实现。

图解:

 

 

以下是自己写的代码。

 

客户号码类

/*

定义一个用于存储上一个客户号码的成员变量和用于存储所有等待服务的客户号码的队列集合。
定义一个产生新号码的方法和获取马上要为之服务的号码的方法,这两个方法被不同的线程操作了相同的数据,所以,要进行同步。(我刚做时就漏掉了)
*/


public class NumberManager {
 //创建一个装客户号码的集合
 private ArrayList<String> NumberCol = new ArrayList<String>();
 //定义一个计算号码的变量
 private int lastNumber = 0;
 //生成号码方法,往集合添加号码(目前好像加不加锁都没问题,因为只有一条线程生成这种类型的号码,但是由于这个方法对里面变量进行了修改,还是加上锁比较安全)
 public synchronized void generateNumber(){
  NumberCol.add(++lastNumber+"");
 }
 //获得号码的方法,需要删除集合的第一个元素(必须加锁,因为有可能多个窗口对象一起操作普通客户号码)
 public synchronized String getNumber(){
  if(NumberCol.isEmpty()){return "";}
  return NumberCol.remove(0);
 }
 //取得最后号码数
 public int getLastNumber(){
  return lastNumber;
 }
}

 

号码机器类

/*

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


public class NumberMachine {
 private static NumberMachine instance = new NumberMachine();
 
 private NumberMachine(){}
 //使用单例
 public static NumberMachine getInstance(){
  return instance;
 }

 //创建普通客户对象
 private static NumberManager commonManager = new NumberManager();
 //创建快速客户对象
 private static NumberManager quickManager = new NumberManager();
 //创建VIP客户对象
 private static NumberManager VIPManager = new NumberManager();
 //得到各类型客户对象的方法
 public static NumberManager getCommonManager(){
  return commonManager;
 }
 public static NumberManager getQuickManager(){
  return quickManager;
 }
 public static NumberManager getVIPManager(){
  return VIPManager;
 }
}

 

服务窗口类

/*

定义一个service方法,内部启动一个线程,根据服务窗口的类别分别循环调用三个不同的方法。
定义三个方法分别对三种客户进行服务,为了观察运行效果,应详细打印出其中的细节信息。
*/

 

public class ServiceWindow {
 //定义一个客户类型变量
 private ManagerType type;
 //定义一个int型变量,主要是区分第几个服务窗口
 private int number;
 //get和set方法
 public ManagerType getType() {
  return type;
 }
 public void setType(ManagerType type) {
  this.type = type;
 }
 public ServiceWindow(int number){
  this.number = number;
 }
 //开启窗口服务(开启线程)
 public void service(){
  //创建一个单线程
  Executor es =Executors.newSingleThreadExecutor();
  es.execute(new Runnable(){
   public void run(){
    while(true){
     //判断这个窗口要处理的是什么类型,做相应的操作
     switch(type){
     case COMMON:
      commonService();
      break;
     case QUICK:
      quickService();
      break;
     case VIP:
      vipService();
      break;
     }
    }
   }
  });
 }
 //普通客户服务方法
 public void commonService(){
  //获取窗口名字
  String serviceName = "第"+number+"号"+type+"窗口";
  //取得号码
  String numberManager = NumberMachine.getCommonManager().getNumber();
  //判断是否“”,如果不是,证明有客户正在等待
  if(numberManager!=""){
   //获得随机1到10秒的时间,为了休眠
   int time = new Random().nextInt((Constant.MAX_TIME-Constant.MIN_TIME))+1+Constant.MIN_TIME;
   //输出语句
   System.out.println(serviceName+"正在为"+numberManager+"号普通客户服务");
   try {
    //休眠随机时间
    Thread.sleep(time);
    //输出服务花费时间
    System.out.println(serviceName+"完成任务,耗时"+time/1000+"秒");
   } catch (Exception e) {
    e.printStackTrace();
   }
  }
  else{
   try {
    //如果没有客户等待,休眠1秒后继续服务
    Thread.sleep(1000);
   } catch (Exception e) {
    e.printStackTrace();
   }
  }
 }
 //快速客户服务方法
 public void quickService(){
  //获得窗口名字
  String serviceName = "第"+number+"号"+type+"窗口";
  //获得快速客户号码
  String numberManager = NumberMachine.getQuickManager().getNumber();
  //判断是否有快速客户
  if(numberManager!=""){
   //获得随机1到10秒的时间,为了休眠
   int time = new Random().nextInt((Constant.MAX_TIME-Constant.MIN_TIME))+1+Constant.MIN_TIME;
   System.out.println(serviceName+"正在为"+numberManager+"号快速客户服务");
   try {
    Thread.sleep(time);
    //输出服务花费时间
    System.out.println(serviceName+"完成任务,耗时"+time/1000+"秒");
   } catch (Exception e) {
    e.printStackTrace();
   }
  }
  else{
   try {
    //休眠1秒,转为普通窗口
    Thread.sleep(1000);
    System.out.println(serviceName+"没有服务,转为普通窗口");
    //调用普通窗口方法
    commonService();
   } catch (Exception e) {
    e.printStackTrace();
   }
  }
  
 }
 //VIP客户服务方法
 public void vipService(){
  //获得窗口名字
  String serviceName = "第"+number+"号"+type+"窗口";
  //获得vip客户号码
  String numberManager = NumberMachine.getVIPManager().getNumber();
  //判断是否有VIP客户
  if(numberManager!=""){
   int time = new Random().nextInt((Constant.MAX_TIME-Constant.MIN_TIME))+1+Constant.MIN_TIME;
   System.out.println(serviceName+"正在为"+numberManager+"号VIP客户服务");
   try {
    Thread.sleep(time);
    //输出服务花费时间
    System.out.println(serviceName+"完成任务,耗时"+time/1000+"秒");
   } catch (Exception e) {
    e.printStackTrace();
   }
  }
  else{
   try {
    //休眠1秒,转为普通窗口
    Thread.sleep(1000);
    System.out.println(serviceName+"没有服务,转为普通窗口");
    //调用普通窗口方法
    commonService();
    
   } catch (Exception e) {
    e.printStackTrace();
   }
  }
 }
}

 客户类型,使用枚举

/*

系统中有三种类型的客户,所以用定义一个枚举类,其中定义三个成员分别表示三种类型的客户。
重写toString方法,返回类型的中文名称。

public enum ManagerType {
 COMMON,QUICK,VIP;
 //重写toString方法
 public String toString(){
  String type = "";
  switch(this){
  case COMMON:
   type = "COMMON";
   break;
  case QUICK:
   type = "QUICK";
   break;
  case VIP:
   type = "VIP";
   break;
  
  }
  return type;
  
 }
}

 

定义一个专门定义常量的类,主要是为了方便操作


public class Constant {
 //定义最短时间
 public static final int MIN_TIME = 1000;
 //定义最长时间
 public static final int MAX_TIME = 10000;
 //定义服务时间
 public static final int SERVICE_TIME = 1;
}

 

主类(这里的方法和张老师的方法有点不同,但实现都是一样的)

/*

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

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

*/


public class MainClass {

 
 public static void main(String[] args) {
  //创建4个普通窗口,编号从1开始
  for(int i = 1;i<5;i++){
  toService(ManagerType.COMMON,i);
  }
  //创建1个快速窗口
  toService(ManagerType.QUICK,1);
  //创建1个vip窗口
  toService(ManagerType.VIP,1);
  //generate方法,根据不同时间生成3个不同类型的客户
  generate(ManagerType.COMMON,Constant.SERVICE_TIME);
  generate(ManagerType.QUICK,Constant.SERVICE_TIME*3);
  generate(ManagerType.VIP,Constant.SERVICE_TIME*6);
 }

 //创建服务窗口的方法
 private static void toService(ManagerType type,int i) {
  //创建服务窗口
  ServiceWindow window = new ServiceWindow(i);
  //设置窗口服务类型
  window.setType(type);
  //开启窗口服务
  window.service();
 }
 //创建生成客户的方法,需要传入类型和时间
 private static void generate(final ManagerType type,int time){
  //创建定时器
  ScheduledExecutorService ses = Executors.newScheduledThreadPool(1);
  ses.scheduleAtFixedRate(new Runnable(){
   public void run(){
    //由于生成客户方法有点相像,所以我把他抽成了generateNumber方法,传入一个客户类型
    generateNumber(type);
   }
  },
    time,
    time,
    TimeUnit.SECONDS); 
 }
 //生成客户方法
 private static void generateNumber(ManagerType type){
  switch(type){
  case COMMON:
   //生成普通客户号码牌
   NumberMachine.getCommonManager().generateNumber();
   System.out.println(NumberMachine.getCommonManager().getLastNumber()+"个普通客户正在等待服务");
   break;
  case QUICK:
   //生成快速客户号码牌
   NumberMachine.getQuickManager().generateNumber();
   System.out.println(NumberMachine.getQuickManager().getLastNumber()+"个快速客户正在等待服务");
   break;
  case VIP:
   //生成VIP客户号码牌
   NumberMachine.getVIPManager().generateNumber();
   System.out.println(NumberMachine.getVIPManager().getLastNumber()+"个VIP客户正在等待服务");
   break;
  }
 }

}

 

程序运行结果:

写这份代码时感到有点困难的是ServiceWindow这个类,因为这个类设计得有点巧,我第一次写这份代码时没有传type也没有写常量类,直接把数字和字符串写进去,既不灵活,可读性又差还越写越复杂。第二次把这些都准备好之后,感觉一下清晰多了,还是张老师考虑周到,我写代码还是有点欠缺火候。

 


 

 


原创粉丝点击