银行业务调度系统

来源:互联网 发布:金秀贤是否过气了 知乎 编辑:程序博客网 时间:2024/05/16 15:13

银行业务调度系统---模拟实现银行业务调度系统逻辑,具体需求如下:
 
 银行内有6个业务窗口,1 - 4号窗口为普通窗口,5号窗口为快速窗口,6号窗口为VIP窗口。
 
 有三种对应类型的客户:VIP客户,普通客户,快速客户(办理如交水电费、电话费之类业务的客户)。
 
异步随机生成各种类型的客户,生成各类型用户的概率比例为:
 
        VIP客户 :普通客户 :快速客户  =  1 :6 :3。
 
 客户办理业务所需时间有最大值和最小值,在该范围内随机设定每个VIP客户以及普通客户办理业务所需的时间,快速客户办理业务所需时间为最小值(提示:办理业务的过程可通过线程Sleep的方式模拟)。
 
 各类型客户在其对应窗口按顺序依次办理业务。 
 
 当VIP(6号)窗口和快速业务(5号)窗口没有客户等待办理业务的时候,这两个窗口可以处理普通客户的业务,而一旦有对应的客户等待办理业务的时候,则优先处理对应客户的业务。
 
 随机生成客户时间间隔以及业务办理时间最大值和最小值自定,可以设置。
 
 不要求实现GUI,只考虑系统逻辑实现,可通过Log方式展现程序运行结果。
 
用面向对象思维进行分析:
有三种对应类型的客户:VIP客户,普通客户,快速客户 ,异步随机生成各种类型的客户,各类型客户在其对应窗口按顺序依次办理业务 。
首先,经常在银行办理业务的人更有利于理解本系统,例如,我经常陪老婆跑银行,对银行的这个业务算是比较熟悉了,我知道每一个客户其实就是由银行的一个取号机器产生号码的方式来表示的。所以,我想到要有一个号码管理器对象,让这个对象不断地产生号码,就等于随机生成了客户。
由于有三类客户,每类客户的号码编排都是完全独立的,所以,我想到本系统一共要产生三个号码管理器对象,各自管理一类用户的排队号码。这三个号码管理器对象统一由一个号码机器进行管理,这个号码机器在整个系统中始终只能有一个,所以,它要被设计成单例。
各类型客户在其对应窗口按顺序依次办理业务 ,准确地说,应该是窗口依次叫号。
各个窗口怎么知道该叫哪一个号了呢?它一定是问的相应的号码管理器,即服务窗口每次找号码管理器获取当前要被服务的号码。
如果我不是多次亲身经历银行的这种业务,再加之积累了大量面向对象的应用开发经验,我也不知道能否轻松进行这种设计,能否发掘出其中隐含的对象信息.


具体到: NumberManager类
定义一个用于存储上一个客户号码的成员变量和用于存储所有等待服务的客户号码的队列集合。
定义一个产生新号码的方法和获取马上要为之服务的号码的方法,这两个方法被不同的线程操作了相同的数据,所以,要进行同步。
NumberMachine类
定义三个成员变量分别指向三个NumberManager对象,分别表示普通、快速和VIP客户的号码管理器,定义三个对应的方法来返回这三个NumberManager对象。
将NumberMachine类设计成单例。
[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
package cn.itcast.bank;  
  
import java.util.ArrayList;  
import java.util.List;  
//一个号码,就代表一个人.-----联想实际银行业务.  
  
public class NumberManager {  
    //上一次返回的号码  
    private int lastNumber=1;  
  
    //存储排队的号码//面向接口编程---变量类型尽量用[上级]----即使不用ArrayList,用LinkedList也照样没问题.  
    private List<Integer> queueNumber=new ArrayList<Integer>();  
  
      
      
      
    //生成号码----客户调用该方法  
    public synchronized Integer generateNewManager(){  
        queueNumber.add(lastNumber);  
        return lastNumber++;  
    }  
      
      
      
    //取号码----窗口调用该方法  
    public synchronized Integer fetchServiceNumber(){  
        Integer number=null;  
  
        //动数据前,先检查数据是否存在  
        if(queueNumber.size()>0){  
        return  number=queueNumber.remove(0);  
        }  
        return null;  
    }  
}  



//模拟实际的取号机器  
  
public class NumberMachine {//Machine[机器]  
    //普通  
    private NumberManager commonManager=new NumberManager();  
    //快速  
    private NumberManager expressManager=new NumberManager();  
    //Vip  
    private NumberManager vipManager=new NumberManager();  
//get获取这三个管理--实例  
    public NumberManager getCommonManager() {  
        return commonManager;  
    }  
    public NumberManager getExpressManager() {  
        return expressManager;  
    }  
    public NumberManager getVipManager() {  
        return vipManager;  
    }  
      
//机器就一个-----所以用单例---  
    private NumberMachine(){}//构造方法私有化  
    private static  NumberMachine instance=new NumberMachine();//来一个独立的实例   
    //因为是单例所以一定要来个获取该类的一个独立的实例  
    public static NumberMachine getInstance(){  
        return instance;  
    }  
      
}  


具体到:CustomerType枚举类
系统中有三种类型的客户,所以用定义一个枚举类,其中定义三个成员分别表示三种类型的客户。
重写toString方法,返回类型的中文名称。这是在后面编码时重构出来的,刚开始不用考虑。
ServiceWindow类
定义一个start方法,内部启动一个线程,根据服务窗口的类别分别循环调用三个不同的方法。 
定义三个方法分别对三种客户进行服务,为了观察运行效果,应详细打印出其中的细节信息。


//客户类型  
public enum CustomerType {  
        COMMON,EXPRESS,VIP;  
          
        @Override//覆盖toString()方法,返回当前窗口类型的中文------  
        public String toString(){  
            switch(this){//-----this当前这个对象  
            case COMMON:  
                return "普通";//return后就直接跳出switch,不用搞break了  
            case EXPRESS:  
                return "快速";  
            case VIP:  
                return name();  
            }  
            return null;  
        }  
}  



package cn.itcast.bank;  
import java.util.Random;  
import java.util.concurrent.ExecutorService;  
import java.util.concurrent.Executors;  
  
//模拟----银行中的窗口  
  
public class ServiceWindows {  
    //存储窗口的类型---因为只有三种类型,所以建议用枚举  
    private CustomerType type=CustomerType.COMMON;//缺省值为普通  
    //存储抽口的ID  
    private int windowID=1;//默认为1  
      
      
    public void setType(CustomerType type) {  
        this.type = type;  
    }  
    public void setWindowID(int windowID) {  
        this.windowID = windowID;  
    }  
      
      
    //在启动方法中,来一个线程---来实现  
    public void start(){  
        ExecutorService pool=Executors.newSingleThreadExecutor();//单一线程池--1.5新技术  
        pool.execute(new Runnable(){  
            @Override  
            public void run() {  
                while(true){//------去不停的取号码while循环---  
                    switch(type){//------给出一个枚举条件,看他到底是属于那个客户类型  
                    case COMMON:  
                        commonService();  
                            break;  
                    case EXPRESS:  
                        expressService();  
                        break;  
                    case VIP:  
                        vipService();  
                        break;  
                    }  
                }  
            }  
        });  
    }  
      
      
    private void commonService() {  
        String windowName="第"+windowID+"号"+type+"窗口";//当前窗口的名字  
        //启动了该窗口后,就要打印出状态----正在获取任务  
        System.out.println(windowName+"正在获取任务");  
          
        //去拿一个普通客户的号码  
        Integer number= NumberMachine.getInstance().getCommonManager().fetchServiceNumber();  
        if(number!=null){//判断,当前是否拿到了号码  
            //当拿到号码后----  
            long beginTime=System.currentTimeMillis();//开始服务--记下时间值  
            //************************************************************************************************  
            System.out.println(windowName+"正在为第"+number+"号"+type+"客户服务");  
              
            int maxRand=Constants.MAX_SERVICE_TIME-Constants.MIN_SERVICE_TIME;//最大的随机数10000-1000=9000  
            //随机产生出1000(包含最小值)~10000(包含最大值)----基数为1000,随机数为0~9000[包含0和9000]  
            long serveTime=new Random().nextInt(maxRand+1)+Constants.MIN_SERVICE_TIME;  
              
            try {  
                Thread.sleep(serveTime);  
            } catch (InterruptedException e) {  
                e.printStackTrace();  
            }  
            //************************************************************************************************            
            long costTime=System.currentTimeMillis()-beginTime;//服务完成--算出耗费的时间  
            System.out.println(windowName+"为第"+number+"号"+type+"客户完成服务,耗时"+costTime/1000+"秒(S)");  
        }else{//没有拿到号码后----  
            System.out.println(windowName+"没有取到任务,先休息1秒钟");  
            try {  
                Thread.sleep(1000);  
            } catch (InterruptedException e) {  
                e.printStackTrace();  
            }  
        }  
    }  
      
      
      
    private void expressService() {  
        String windowName="第"+windowID+"号"+type+"窗口";  
        System.out.println(windowName+"正在获取任务");  
          
        Integer number= NumberMachine.getInstance().getExpressManager().fetchServiceNumber();  
        if(number!=null){  
            long beginTime=System.currentTimeMillis();  
            System.out.println(windowName+"正在为第"+number+"号"+type+"客户服务");  
              
            try {  
                Thread.sleep(Constants.MIN_SERVICE_TIME);//快速窗口---每次服务均为最小值  
            } catch (InterruptedException e) {  
                e.printStackTrace();  
            }  
              
            long costTime=System.currentTimeMillis()-beginTime;  
            System.out.println(windowName+"为第"+number+"号"+type+"客户完成服务,耗时"+costTime/1000+"秒(S)");  
        }else{  
            System.out.println(windowName+"没有取到任务,去获取普通任务");  
            commonService();  
        }  
    }  
      
    private void vipService() {  
        String windowName="第"+windowID+"号"+type+"窗口";  
        System.out.println(windowName+"正在获取任务");  
          
        Integer number= NumberMachine.getInstance().getVipManager().fetchServiceNumber();  
        if(number!=null){  
            long beginTime=System.currentTimeMillis();  
            System.out.println(windowName+"正在为第"+number+"号"+type+"客户服务");  
              
            int maxRand=Constants.MAX_SERVICE_TIME-Constants.MIN_SERVICE_TIME;//最大的随机数10000-1000=9000  
            //随机产生出1000(包含最小值)~10000(包含最大值)----基数为1000,随机数为0~9000[包含0和9000]  
            long serveTime=new Random().nextInt(maxRand+1)+Constants.MIN_SERVICE_TIME;  
              
            try {  
                Thread.sleep(serveTime);  
            } catch (InterruptedException e) {  
                e.printStackTrace();  
            }  
              
            long costTime=System.currentTimeMillis()-beginTime;  
            System.out.println(windowName+"为第"+number+"号"+type+"客户完成服务,耗时"+costTime/1000+"秒(S)");  
        }else{  
            System.out.println(windowName+"没有取到任务! 去获取普通任务");  
            commonService();  
        }  
    }  
      
      
      
}  


具体到:MainClass类
用for循环创建出4个普通窗口,再创建出1个快速窗口和一个VIP窗口。
接着再创建三个定时器,分别定时去创建新的普通客户号码、新的快速客户号码、新的VIP客户号码。
Constants类
定义三个常量:MAX_SERVICE_TIME、MIN_SERVICE_TIME、COMMON_CUSTOMER_INTERVAL_TIME
[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
package cn.itcast.bank;  
//常量---要定义一个专门的类  
public class Constants {  
    public final static int MAX_SERVICE_TIME=10000;//最大服务时间  
    public final static int MIN_SERVICE_TIME=1000;//最小服务时间  
      
    public static final int COMON_CUSTOMER_INTERVAL_TIME=1;  
      
}  


[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
package cn.itcast.bank;  
  
import java.util.concurrent.Executors;  
import java.util.concurrent.ScheduledExecutorService;  
import java.util.concurrent.TimeUnit;  
//Main程序的大门  
  
public class MainClass {  
    public static void main(String[] args) {  
          
        //五个普通窗口  
        for(int i=1;i<5;i++){  
            ServiceWindows commonWindow=new ServiceWindows();  
            commonWindow.setWindowID(i);  
            commonWindow.start();  
        }  
          
        //一个快速窗口  
        ServiceWindows expressWindow=new ServiceWindows();  
        expressWindow.setWindowID(5);  
        expressWindow.setType(CustomerType.EXPRESS);  
        expressWindow.start();  
          
        //一个VIP窗口  
        ServiceWindows vipWindow=new ServiceWindows();  
        vipWindow.setWindowID(6);  
        vipWindow.setType(CustomerType.VIP);  
        vipWindow.start();  
          
          
        //生成各类型用户的概率比例---->vip:common:express=1:6:3  
          
          
        //定时发放号码---模拟来[普通客户]的人数  
        Executors.newScheduledThreadPool(1).scheduleAtFixedRate(  
                new Runnable() {  
                    @Override  
                    public void run() {  
                        //创建一个号码  
                        Integer number=NumberMachine.getInstance().getCommonManager().generateNewManager();  
                        System.out.println(number+"号,普通客户等待服务!");  
                    }  
                },  
                0,   
                Constants.COMON_CUSTOMER_INTERVAL_TIME, //一秒钟来一个  
                TimeUnit.SECONDS);  
          
          
          
        //定时发放号码---模拟来[快速客户]的人数  
        Executors.newScheduledThreadPool(1).scheduleAtFixedRate(  
                new Runnable() {  
                    @Override  
                    public void run() {  
                        Integer number=NumberMachine.getInstance().getExpressManager().generateNewManager();  
                        System.out.println(number+"号,快速客户等待服务!");  
                    }  
                },  
                0,   
                Constants.COMON_CUSTOMER_INTERVAL_TIME*2, //两秒钟来一个  
                TimeUnit.SECONDS);  
          
          
          
        //定时发放号码---模拟来[VIP客户]的人数  
        Executors.newScheduledThreadPool(1).scheduleAtFixedRate(  
                new Runnable() {  
                    @Override  
                    public void run() {  
                        Integer number=NumberMachine.getInstance().getVipManager().generateNewManager();  
                        System.out.println(number+"号,Vip客户等待服务!");  
                    }  
                },  
                0,   
                Constants.COMON_CUSTOMER_INTERVAL_TIME*6, //六秒钟来一个  
                TimeUnit.SECONDS);  
}  
}  
0 0