银行业务调度系统的项目

这是我第一个博客,这个是从其他网站上找来的资料,并用自己的理解来写的,有很多不对的地方请包涵,最后我会附上 张孝祥-7K月薪面试题破解之二_银行业务调度系统视频教程 原文件。

银行业务调度系统的项目需求
模拟实现银行业务调度系统逻辑,具体需求如下:
*银行内有6个业务窗口,1 - 4号窗口为普通窗口,5号窗口为快速窗口,6号窗口为VIP窗口。
有三种对应类型的客户:VIP客户,普通客户,快速客户(办理如交水电费、电话费之类业务的客户)。
异步随机生成各种类型的客户,生成各类型用户的概率比例为:
VIP客户 :普通客户 :快速客户 = 1 :6 :3。
客户办理业务所需时间有最大值和最小值,在该范围内随机设定每个VIP客户以及普通客户办理业务所需的时间,快速客户办理业务所需时间为最小值(提示:办理业务的过程可通过线程Sleep的方式模拟)
各类型客户在其对应窗口按顺序依次办理业务。
当VIP(6号)窗口和快速业务(5号)窗口没有客户等待办理业务的时候,这两个窗口可以处理普通客户的业务,而一旦有对应的客户等待办理业务的时候,则优先处理对应客户的业务。
随机生成客户时间间隔以及业务办理时间最大值和最小值自定,可以设置。
不要求实现GUI,只考虑系统逻辑实现,可通过Log方式展现程序运行结果。*

分析该需求,java是面向对象,我们需要从该需求中找到相关的对象,然后在从其中找属性和方法。
结合实际,我们可以找到客户类,窗口类,机器类(该类是从实际情况中分析出来的)。
客户类属性:姓名
窗口类属性:窗口编号,窗口姓名。
机器类属性:该机器中有三个管理类,一个是普通号管理类,一个是快速管理类,一个是VIP管理类,管理类中包涵了来的客户的编号,和需要维护的客户队列。

这个分析是慢慢的积累出来的,也有一些课程来,比如UML中类的课程就讲了怎样找类和类的属性、方法。而且找类后在实际编写代码时都有可能在分出类来,这些类是实际需要。
客户类:由于该程序很小,客户类中没有其他的东西,只有一个名字属性,并且不需要客户该对象。这里我们可以创建一个enum,该类中有三个COMMON,FAST,VIP分别表示普通客户,快速客户,vip客户。

 public enum Customer {
    COMMON, FAST, VIP;
    public String toString() {
        String name = null;
        switch (this) {
        case COMMON:
            name = "普通";
        case FAST:
            name = "快速";
        case VIP:
            name = name();
        }
        return name;
    }
}
  该enum中重写了toString()方法,这是用户返回一组汉字。
  这样客户类创建好了

  窗口类中属性窗口编号,窗口名称
  方法:叫号方法
  从实际中,我们可以发现银行的窗口叫号,然后客户才来
  public class WindonService {
    private Customer name = Customer.COMMON;        //窗口名称
    private int number = 1;     //窗口编号


    /**
     * 要完成的任务
     */
    public void start(){
        //开启线程来完成
        Executors.newSingleThreadExecutor().execute(new Runnable() {
            @Override
            public void run() {
                while(true){
                    switch (name) {
                    case COMMON:
                        commonService();
                        break;

                    case FAST:
                        fastService();
                        break;

                    case VIP:
                        vipService();
                        break;
                    }
                }
            }
        });

    }

    /**
     *vip窗口叫号服务
     */
    protected void vipService() {
        String windonservice = "第" + number + "号" + name + "窗口";
        System.out.println(windonservice + ",开始获取vip服务!");
        //取号
        Integer serviceNumber = NumberMachine.getIntance().getVipManager().fetchNumber();
        //判断号码是否为空,如果为空,就等待一段时间
        if (serviceNumber != null) {
            System.out.println(windonservice+ "正在为第" + serviceNumber+"vip客户服务");
            //计算服务时间
            //服务时间
            int randomTime = Constans.MAX_TIME - Constans.MIN_TIME;
            int ServiceTime = new Random().nextInt(randomTime)+1 + Constans.MIN_TIME;
            try {
                Thread.sleep(ServiceTime);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(windonservice + "为第" + serviceNumber + "vip客户服务" + ServiceTime/1000 +"时间");
        }else {
            System.out.println("没有取到vip任务,等待一秒钟");
            //取到普通号码,则服务普通号码
            commonService();
        }
    }




    /**
     * 快速窗口叫号服务
     */
    protected void fastService() {
        String windonservice = "第" + number + "号" + name + "窗口";
        System.out.println(windonservice + ",开始获取快速服务!");
        //取号
        Integer serviceNumber = NumberMachine.getIntance().getFastManager().fetchNumber();
        //判断号码是否为空,如果为空,就等待一段时间
        if (serviceNumber != null) {
            System.out.println(windonservice+ "正在为第" + serviceNumber+"快速客户服务");
            //快速服务时间为最小时间
            int serviceTime = Constans.MIN_TIME;
            try {
                Thread.sleep(serviceTime);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(windonservice + "为第" + serviceNumber + "快速客户服务" + serviceTime/1000 +"时间");
        }else {
            System.out.println("没有取到快速任务,等待一秒钟");
            //快速窗口没有取到快速客户的号码,则试着去取普通号码
            //取到普通号码,则服务普通号码
            commonService();
        }
    }

    /**
     * 普通窗口的服务
     */
    protected void commonService() {
        String windonservice = "第" + number + "号" + name + "窗口";
        System.out.println(windonservice + ",开始获取普通服务!");
        //取号
        Integer serviceNumber = NumberMachine.getIntance().getCommonManager().fetchNumber();
        //判断号码是否为空,如果为空,就等待一段时间
        if (serviceNumber != null) {
            System.out.println(windonservice+ "正在为第" + serviceNumber+"普通客户服务");
            //计算服务时间
            //服务时间
            int randomTime = Constans.MAX_TIME - Constans.MIN_TIME;
            int ServiceTime = new Random().nextInt(randomTime)+1 + Constans.MIN_TIME;
            try {
                Thread.sleep(ServiceTime);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(windonservice + "为第" + serviceNumber + "普通客户服务" + ServiceTime/1000 +"时间");
        }else {
            System.out.println("没有取到普通任务,等待一秒钟");
            try {
                Thread.sleep(1000);         //等待一秒钟
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }





    // ---------------------------------------------
    public Customer getName() {
        return name;
    }


    public void setName(Customer name) {
        this.name = name;
    }


    public int getNumber() {
        return number;
    }


    public void setNumber(int number) {
        this.number = number;
    }

}

该类中我没有进行优化。所有每个窗口进行叫号,这样,因为有三个窗口,这样我们进行一下区分,进行start()方法,进入start()中后,会进行判断那一个窗口,并进行相应的方法。
普通窗口叫号时,先取出号码,并判断是否有该号码,没有则等待一分钟在叫,有那么就行该客户服务。该客户服务有一个时间,根据需求,需要在最小时间和最大时间之间的随机值。随后就结束服务。
快速窗口叫号时,先取出号码,并判断是否有该号码,没有,这时需要去询问是否有普通客户,此时直接调用普通窗口叫号服务,有那么就行该客户服务。该客户服务有一个时间,根据需求,直接是最小时间。
快速窗口叫号时,先取出号码,并判断是否有该号码,没有,这时需要去询问是否有普通客户,此时直接调用普通窗口叫号服务,有那么就行该客户服务。该客户服务有一个时间,根据需求,需要在最小时间和最大时间之间的随机值。随后就结束服务。

此时该服务类就可以完成。其中会发现如何去得到一个号码呢。该号码是有机器产生的,这时就需要创建机器类,机器类中来创建一个号码管理器,该号码管理器是管理每个到来客户的一个信息的,比如普通客户到时机器到了几号了,同时要维护每次到来客户的队列。该号码管理器能够产生两个方法,取号,产生号码方法。如下:

public class NumberManager {
    private Integer lastNumber = 0;
    private List<Integer> queueNumber = new ArrayList<Integer>();

    /**
     * 生成号码
     */
    public synchronized Integer generateNumber(){
        queueNumber.add(++lastNumber);
        return lastNumber;
    }
    /**
     * 取号码
     * @return
     */
    public synchronized Integer fetchNumber(){
        if (queueNumber.size() > 0) {
            return queueNumber.remove(0);
        }else {
            return null;
        }
    }
}

机器管理类只需维护三个号码管理器就可以了,在实际中机器只有一台,那么该处用到单例,单例的方法如下:
private Class(){}
private static Class mInstance;
public static Class getInstance(){
if(mInstance == null){//Class为类名
mInstance = new Class();
}
return mInstance;
}

机器管理类如下:

public class NumberMachine {
    /**
     * 由于叫号机器只有一台,必须给其创建单利
     * 机器可以生成三种不同号码,普通号码,快速号码,vip号码
     */
    private NumberMachine(){}
    private static NumberMachine mInstance;

    public static NumberMachine getIntance(){
        if (mInstance== null) {
            mInstance = new NumberMachine();
        }
        return mInstance;
    }

    private NumberManager commonManager = new NumberManager();
    private NumberManager fastManager = new NumberManager();
    private NumberManager vipManager = new NumberManager();

    public NumberManager getCommonManager() {
        return commonManager;
    }
    public NumberManager getFastManager() {
        return fastManager;
    }
    public NumberManager getVipManager() {
        return vipManager;
    }

}

这里有个常量类:

public class Constans {
    public static final int MAX_TIME = 10000;           //最大服务时间是10秒
    public static final int MIN_TIME = 1000;            //最小服务时间是1秒
}

那么这时完成大部分功能了,有一个功能没有完成,那是怎样随机产生客户,这个会在主方法中完成:
主方法要完成两个功能:
分别创建6个窗口;
按要求产生客户;

按比例产生号码,我想到了使用scheduleAtFixedRate,该方法是周期性的完成任务。其中调用时,有四个参数,一个参数是Runnable,是要完成需要执行的方法,initialDelay 初始延迟时间,period周期,TimeUnit周期的时间单位。
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
}
}, 0, 1, TimeUnit.SECONDS);
这是该方法的调用。

    public static void main(String[] args) {
        /**
         * 创建出6个窗口来
         * 然后机器运行起来,生成号码
         */
        for (int i = 1; i < 5; i++) {   //创建4个普通窗口
            WindonService commonService = new WindonService();
            commonService.setName(Customer.FAST);
            commonService.start();
        }

        WindonService fastService = new WindonService();    //创建1个快速窗口
        fastService.setName(Customer.VIP);
        fastService.start();

        WindonService vipService = new WindonService(); //创建1个vip窗口
        vipService.setNumber(1);
        vipService.start();

        Executors.newScheduledThreadPool(1).scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                Integer serviceNumber = NumberMachine.getIntance().getCommonManager().generateNumber();
                System.out.println("第" + serviceNumber + "号普通客户正在等待服务!");
            }
        }, 0, 1, TimeUnit.SECONDS);

        Executors.newScheduledThreadPool(1).scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                Integer serviceNumber = NumberMachine.getIntance().getFastManager().generateNumber();
                System.out.println("第" + serviceNumber + "号快速客户正在等待服务!");
            }
        }, 0, 3, TimeUnit.SECONDS);

        Executors.newScheduledThreadPool(1).scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                Integer serviceNumber = NumberMachine.getIntance().getVipManager().generateNumber();
                System.out.println("第" + serviceNumber + "号vip客户正在等待服务!");
            }
        }, 0, 6, TimeUnit.SECONDS);
    }

总结:
第一结合实际我们要找到有哪几个类,并且确定该类要完成的那个属性和方法。那个接下来的工作就很简单了。
那面我就是找到几个类,最后在主方法中进行创建相关的对象。这里还需要有一些经验的地方是scheduleAtFixedRate,该方法的使用。
大家可以下在下列视屏看

参考:

张孝祥-7K月薪面试题破解之二_银行业务调度系统视频教程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值