模拟银行业务办理-java

模拟银行业务办理


一、题目要求

1.模拟客户可以随机办理银行提供的8种业务中的一种;期中办理时间规划为:(基准时间每个同学自行指定) 完成

业务 业务序号 办理时间 * benchMarkTime
存款 1 0.5-1.5
取款 2 0.5-1.5
缴纳罚款 3 1.2-2.0
开通网银 4 5.0-8.0
交水电费 5 1.5-2.0
购买基金 6 2.0-3.0
转账汇款 7 3.0-4.0
个贷还款 8 2.0-4.0

2.程序模拟多个窗口服务,窗口服务具有一定的差异化,现在窗口的开放情况如下 完成

窗口来信 能办理业务类型 说明 数量
A类窗口 1,2,3,4,5,6,7,8 所有客户可以办理 1
B类窗口 1,2,4,5,7 所有客户可以办理 2
V类窗口 1,2,3,4,5,6,7,8 vip客户优先 1

3.顾客模拟要求: 完成

  • 3.1 顾客分为普通客户和VIP客户,普通用户和VIP客户比例自行确定
  • 3.2 顾客到达随机模拟

4.模拟程序模拟一天的营业情况,在完成当天的营业(模拟为上午8:00-下午17:00)后打印出客户列表,包括: 完成

  • 客户名称
  • 客户到达时间
  • 客户办理业务类型
  • 客户所用时间

5.统计出以下数据: 完成

  • 5.1 当天的所有顾客平均办理时间(从到达到办理完成时间定义为顾客办理时间)
  • 5.2 不同业务在所有办理业务中所占的比例

6.仿真(*需要评定优秀的同学需要提供此部分实现):

  • 6.1 程序能够参数化设定当天到达客户办理不同业务的比例(比如业务1占20%等) 完成
  • 6.2 程序能够模拟回答以下问题:如果基准日开放的窗口情况为: 未完成

A类:1个
B类:2个
V类:1个

那么针对营业日B的情况,在相同顾客数量的情况下,要如何开发窗口才能得到和基准日基本一致的顾客平均服务时间;

业务 基准日A 基准日B
存款 20% 10%
取款 20% 10%
缴纳罚款 10% 5%
开通网银 10% 5%
交水电费 5% 5%
购买基金 15% 40%
转账汇款 10% 5%
个贷还款 10% 20%

二、类的划分

Customer

private String name;//顾客名字
private boolean ifVIP;//是否为vip(具体的vip分配看bank类(main))
private AWindows aWindows;//办理业务的A类窗口
private BWindows bWindows;//办理业务的B类窗口
private VWindows vipWindows;//办理业务的V类窗口
private String WindowsName;//本顾客对应的窗口名字
private Task task;//本顾客对应的业务类型
private Service service;//对应的enum
private long birthTime;//顾客到达时间
private long endTime;//顾客离开时间

Service

//enum Service
Deposit(1),DrawMoney(2),Forfeit(3),EBank(4),WaterEle(5),Fund(6),TransAccount(7),RepayLoan(8);

public int index;//通过下标寻找具体办理业务
public double minTime;//最短办理时间
public double maxTime;//最长办理时间
public static final double benchMarkTime = 10 ;//基准时间为10分钟 “单位:分”

Task

private SimpleDateFormat dateFormat =new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//时间格式定义
private int costTime;// 业务需要消耗的时间
private Calendar birthTime;// 业务生成时间
private Calendar startTime;// 业务开始时间
private Calendar endTime;// 业务结束时间
private Integer TaskID;//业务序号

AWindows(BWindows / VWindows)三个类放在一起介绍

//extends Thread
public String name;//窗口名字
protected ArrayList<BlockingQueue<Customer>> CustomerQueue = null;// 客户队列容器,每个窗口至少有一个客户队列

private BlockingQueue<Customer> BlockingQueue;//A有三个队列 B与V只有一个
private BlockingQueue<Customer> BlockingQueue1;
private BlockingQueue<Customer> BlockingQueue2;

MathRandomTask(实现分配各业务的概率)

public static double rate1 = 0.20;//1出现的概率为%20
public static double rate2 = 0.20;//2出现的概率为%20
public static double rate3 = 0.10;//3出现的概率为%10
public static double rate4 = 0.10;//4出现的概率为%10
public static double rate5 = 0.05;//5出现的概率为%5
public static double rate6 = 0.15;//6出现的概率为%15
public static double rate7 = 0.10;//7出现的概率为%10
public static double rate8 = 0.10;//8出现的概率为%10

bank(main函数)

public static int count = 1;//银行单子序号
public static int Minute =10; //多少分钟来一个顾客
public static int Time = (17-8)*60;//每天营业时间
static SimpleDateFormat format = new SimpleDateFormat("yyyy-mm-dd HH:mm:ss");
public static long millis;//开门时间
public static long closeDoor;//关门时间
public static Calendar calendar;//银行开门的时间/ 开始执行项目的具体时间
public static int aNUM=0;//A类窗口服务人数
public static int bNUM=0;//B类窗口服务人数
public static int vNUM=0;//V类窗口服务人数
static BlockingQueue<Customer> Queue = new ArrayBlockingQueue<Customer>(200);
static BlockingQueue<Customer> Queue1 = new ArrayBlockingQueue<Customer>(200);

三、核心代码

Customer、Task(都是Getter and Setter)

Service

通过下标index值 找到具体业务(返回Service)

public static Service getServiceByIndex(int index){
    for (Service s : values()){
        if( s.getIndex() == index){
            return s;
        }
    }
    return null;
}

在maxTime与minTime之间随机生成一个时间成为本业务所耗费时间

public static int needSeconds(Service service){
    return (int)(new Random().nextInt((int)service.maxTime)%(service.maxTime-service.minTime+1) + service.minTime);
}

当确定enum的具体值时,自动生成maxTime与minTime

    Service(int index){
    this.index = index;
    switch (index){
        case 1:
        case 2:
            this.minTime = 0.5 * 50 * benchMarkTime/Minute;
            this.maxTime = 1.5 * 50 * benchMarkTime/Minute;
            break;
        case 3:
            this.minTime = 1.2 * 50 * benchMarkTime/Minute;
            this.maxTime = 2.0 * 50 * benchMarkTime/Minute;
            break;
        case 4:
            this.minTime = 5 * 50 * benchMarkTime/Minute;
            this.maxTime = 8 * 50 * benchMarkTime/Minute;
            break;
        case 5:
            this.minTime = 1.5 * 50 * benchMarkTime/Minute;
            this.maxTime = 2.0 * 50 * benchMarkTime/Minute;
            break;
        case 6:
            this.minTime = 2.0 * 50 * benchMarkTime/Minute;
            this.maxTime = 3.0 * 50 * benchMarkTime/Minute;
            break;
        case 7:
            this.minTime = 3.0 * 50 * benchMarkTime/Minute;
            this.maxTime = 4.0 * 50 * benchMarkTime/Minute;
            break;
        case 8:
            this.minTime = 2.0 * 50 * benchMarkTime/Minute;
            this.maxTime = 4.0 * 50 * benchMarkTime/Minute;
            break;
    }
}

MathRandomTask(实现分配各业务的概率)

Math.random()产生一个double型的随机数,判断一下。例如1出现的概率为%20,则介于0到0.20中间的返回1

public int PercentageRandom()
{
    double randomNumber;
    randomNumber = Math.random();
    if (randomNumber >= 0 && randomNumber <= rate1)
    {
        return 1;
    }
    else if (randomNumber >= rate1  && randomNumber <= rate1 + rate2)
    {
        return 2;
    }
    else if (randomNumber >= rate1 + rate2
            && randomNumber <= rate1 + rate2 + rate3)
    {
        return 3;
    }
    else if (randomNumber >= rate1 + rate2 + rate3
            && randomNumber <= rate1 + rate2 + rate3 + rate4)
    {
        return 4;
    }
    else if (randomNumber >= rate1 + rate2 + rate3 + rate4
            && randomNumber <= rate1 + rate2 + rate3 + rate4 + rate5)
    {
        return 5;
    }
    else if (randomNumber >= rate1 + rate2 + rate3 + rate4 + rate5
            && randomNumber <= rate1 + rate2 + rate3 + rate4 + rate5 + rate6)
    {
        return 6;
    }
    else if (randomNumber >= rate1 + rate2 + rate3 + rate4 + rate5 + rate6
            && randomNumber <= rate1 + rate2 + rate3 + rate4 + rate5 + rate6 + rate7)
    {
        return 7;
    }
    else if (randomNumber >= rate1 + rate2 + rate3 + rate4 + rate5 + rate6 + rate7
            && randomNumber <= rate1 + rate2 + rate3 + rate4 + rate5 + rate6 + rate7 + rate8)
    {
        return 8;
    }
    return -1;
}

AWindows(BWindows / VWindows)三个类放在一起介绍

把顾客加入到该窗口的队列中

public void addCustomerQueue(BlockingQueue<Customer> bQueue) {
    if (CustomerQueue == null){
        CustomerQueue = new ArrayList<BlockingQueue<Customer>>();
    }
    CustomerQueue.add(bQueue);
}

从自己的一个或三个窗口队列中获取顾客,并将其从自己的窗口队列中删除

protected Customer getCustomer() throws InterruptedException {
    if (CustomerQueue==null){
        return null;
    }
    if (CustomerQueue.get(0).isEmpty() || CustomerQueue.size() == 1) {// 当自己的客户队列空,或者本本窗口只有属于自己的任务
        return CustomerQueue.get(0).take();// 从对头取出客户,如果客户队列空,则阻塞线程
    }
//        for (int i = 1; i < CustomerQueue.size(); i++) {
//            if (!CustomerQueue.get(i).isEmpty()) {// 存在非空的客户队列,取出客户处理
//                return CustomerQueue.get(i).remove();
//            }
//        }
    return null;
}

多线程的重写 对从窗口队列中获取的顾客进行操作

@Override
public void run(){
    BlockingQueue = CustomerQueue.get(0);
    super.run();
    while (true){
        Customer customer2 = null;
        try {
            synchronized (BlockingQueue) {
                while ((customer2 = getCustomer()) == null) {
                    Thread.sleep(10);
                }
            }
            customer2.setbWindows(this);
            customer2.getTask().setStartTime(Calendar.getInstance());//业务开始的时间
            sleep(customer2.getTask().getCostTime());//处理业务 所以线程暂停时间为业务所花时间
            customer2.getTask().setEndTime(Calendar.getInstance());//结束业务的时间
            customer2.setWindowsName(this.name);

            long birthTime=customer2.getTask().getBirthTime().getTimeInMillis()-calendar.getTimeInMilli();//顾客开始到窗口办理业务
            long endTime = customer2.getTask().getEndTime().getTimeInMillis()-calendar.getTimeInMillis();//顾客离开窗口
            customer2.setBirthTime(birthTime*Minute*60*1000/50+millis);
            customer2.setEndTime(endTime*Minute*60*1000/50+millis);
            aNUM++;//或者bNUM++。或者vNUM++。
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

bank

统计表格的输出(要求第五点)

private static void resultPrint(BlockingQueue<Customer> Queue1) {
    Customer customer = new Customer();
    int Sum = Queue1.size();
    int num1 = 0 ,num2 = 0,num3 = 0,num4 = 0,num5 = 0,num6 = 0,num7 = 0,num8 = 0;
    long time=0;
    while (!Queue1.isEmpty()){
        customer= Queue1.remove();
        time = time + customer.getTask().getCostTime()*72/5;
        switch (customer.getTask().getTaskID()){
            case 1 :
                num1++;break;
            case 2 :
                num2++;break;
            case 3 :
                num3++;break;
            case 4 :
                num4++;break;
            case 5 :
                num5++;break;
            case 6 :
                num6++;break;
            case 7 :
                num7++;break;
            case 8 :
                num8++;break;
        }
    }
    long x = (int)(time/Sum);
    DecimalFormat decimalFormat=new DecimalFormat("0.0000");
    System.out.println("                                              ");
    System.out.println("====================统计表格====================");
    System.out.println("=======业务序号======业务内容======业务比例========");
    System.out.println("         1         Deposit      "+decimalFormat.format((float)num1/(float)Sum));
    System.out.println("         2         DrawMoney    "+decimalFormat.format((float)num2/(float)Sum));
    System.out.println("         3         Forfeit      "+decimalFormat.format((float)num3/(float)Sum));
    System.out.println("         4         EBank        "+decimalFormat.format((float)num4/(float)Sum));
    System.out.println("         5         WaterEle     "+decimalFormat.format((float)num5/(float)Sum));
    System.out.println("         6         Fund         "+decimalFormat.format((float)num6/(float)Sum));
    System.out.println("         7         TransAccount "+decimalFormat.format((float)num7/(float)Sum));
    System.out.println("         8         RepayLoan    "+decimalFormat.format((float)num8/(float)Sum));
    System.out.println("==============================================");
    System.out.println("顾客平均办理时间为:"+x/60+"分"+x%60+"秒");
}

模拟一天的客户列表情况

private static void myPrint(BlockingQueue<Customer> Queue) {
    Customer customer = new Customer();
    long starttime = 0;
    long endtime = 0;
    while (!Queue.isEmpty()){
         customer= Queue.remove();
         if (customer.getWindowsName()==null){
             System.out.println(customer.getName()+"于"+longToDate(starttime)+"到达,在["+"A类窗口"
                     +"]办理了业务序号["+customer.getTask().getTaskID()+"]的"+customer.getService()+"业务。" +"持续"+
                     (customer.getTask().getCostTime()*72/5)/60+"分"+(customer.getTask().getCostTime()*72/5)%60+
                     "秒,顾客离开时间为"+longToDate(endtime));
         }
         else{
             System.out.println(customer.getName()+"于"+longToDate(customer.getBirthTime())+"到达,在["+customer.getWindowsName()
                     +"]办理了业务序号["+customer.getTask().getTaskID()+"]的"+customer.getService()+"业务。" +"持续"+
                     (customer.getTask().getCostTime()*72/5)/60+"分"+(customer.getTask().getCostTime()*72/5)%60+
                     "秒,顾客离开时间为"+longToDate(customer.getEndTime()));
             starttime = customer.getEndTime();
             endtime = customer.getEndTime()+customer.getTask().getCostTime();
         }

    }
}

银行开门

private void excute() {
    /**
     * 创建窗口
     */
    AWindows aWindows = new AWindows("A类窗口");
    BWindows bWindows1 = new BWindows("B类1号窗口");
    BWindows bWindows2 = new BWindows("B类2号窗口");
    VWindows vipWindows = new VWindows("VIP窗口");
    /**
    * vip窗口队列
    */
    BlockingQueue<Customer> VIPQueue = new ArrayBlockingQueue<Customer>(100);
    /**
     *  A窗口队列
     */
    BlockingQueue<Customer> AQueue = new ArrayBlockingQueue<Customer>(100);
    /**
     *  B窗口队列
     */
    BlockingQueue<Customer> BQueue = new ArrayBlockingQueue<Customer>(100);

    /**
     * 添加处于本窗口管理的客户队列
     */
    aWindows.addCustomerQueue(AQueue);
    bWindows1.addCustomerQueue(BQueue);
    bWindows2.addCustomerQueue(BQueue);
    vipWindows.addCustomerQueue(VIPQueue);

    /**
     * 给vip窗口和a窗口添加b类窗口的客户队列
     */
    aWindows.addCustomerQueue(VIPQueue);
    aWindows.addCustomerQueue(BQueue);

    aWindows.start();
    bWindows1.start();
    bWindows2.start();
    vipWindows.start();

    while (true){
        try {
            Customer customer = new Customer();
            customer = InitCustomer();//初始化顾客(随机生成vip及业务序号)
            if (customer.isIfVIP())
                    VIPQueue.add(customer);
            else if (customer.getTask().getTaskID()==3||customer.getTask().getTaskID()==6||customer.getTask().getTaskID()==8)
                    AQueue.add(customer);
            else
                    BQueue.add(customer);
            sleep(50);
            Queue.add(customer);
            Queue1.add(customer);
            if (closeDoor<customer.getEndTime()){
                break;
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
    try {
        sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

long转date

public static String longToDate(long lo){
    Date date = new Date(lo);
    SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    return sd.format(date);
}

顾客初始化

public Customer InitCustomer() {//vip概率为0.3

    Customer customer = new Customer();

    Task task = new Task();
    if (new Random().nextInt(100)<30)//vip概率为0.3由此确定
        customer.setIfVIP(true);
    else
        customer.setIfVIP(false);

    MathRandomTask a = new MathRandomTask();//随机生成业务序号
    int x =a.PercentageRandom();//得到具体数字
    Service service = Service.getServiceByIndex(x);
    task.setBirthTime(Calendar.getInstance());//生成业务的时间
    task.setTaskID(x);//业务序号x
    customer.setTask(task);//衔接Task和Customer
    customer.setService(service);//衔接Service和Customer
    customer.setName("客户"+count);
    customer.getTask().setCostTime(needSeconds(customer.getService()));//把service中预测的时间存入task的costtime中
    count++;
    return customer;
}

总结

整体思路

首先,我将整个银行的模拟从8:00-17:00 九个小时等比例缩放成几秒,跑完整个代码的同时记录下各个时间节点与时间段,例如三十分钟与100毫秒等价,通过以下的函数

Calendar.getInstance()//获取时间点
sleep()//处理业务,暂停时间即为业务所花费时间

来获取时间。整个银行模拟在几秒内跑完,再等比例放大到九个小时,实现模拟。

结果

客户列表

image
image

统计表格

image

以上的要求除了6.2未完成,均已完成

github:https://github.com/zhangjunze1/Simulation_bank

posted @ 2020-11-30 21:34  馒头winner  阅读(769)  评论(0编辑  收藏  举报