黑马程序员——7K面试题之银行业务调度系统

时间:2023-02-18 10:38:31

---------------------- android培训java培训、期待与您交流! ----------------------

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

银行业务调度系统首先要从取号开始,取号又必须在取号机上面进行, 不同的客户会进行不同的业务,所以他们会选择的窗口类型也会 不一样,所以首先我们要定义管理号码器的类NumberManager类,该类
定义一个用于存储上一个客户号码的成员变量和用于存储所有等待服务的客户号码的队列集合,还定义一个产生新号码的方法和获取马上要为之服务的号码的方法,这两个方法被不同的线程操作了相同的数据,所以,要进行同步

这里可以想到用3个类,票,出票机,窗口来模拟整个银行系统运行;

1、票类要有票号属性,等待服务队列;还有有2个方法,出票,票被回收(这里是被叫到客户拿票去办理服务完毕);

2、出票机根据要求要有3个出票口,普通,快速,VIP,所以它有这些属性;出票机只能一台,这里要用到单例模式设计出票机;

3、银行窗口,根据要求要有普通,快速,VIP三种窗口,这里想到用枚举会比较简便;银行窗口有一个方法开始服务;而在方法内比较根据不同的窗口对不同客户办理业务;这里将来需要多个窗口同时进行用了线程,这里我为了提高性能使用线程池;

4、main函数中创建4个普通窗口,模拟客户取票;


票类TicketMessage

 

 
   

package bank.demo;

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

public class TicketMessage {  //票信息类;  //票具有票号属性,等待服务队列方法,产生票方法;  private int ticketNum=1;  private List<Integer> waitList=new ArrayList<Integer>() ;  public synchronized Integer  getTicket(){   waitList.add(ticketNum);   return ticketNum++;  }  public synchronized Integer serviceTicket(){   //这里注意服务号可能为空;   Integer waitNum=null;   if(waitList.size()!=0)    waitNum=waitList.remove(0);   return waitNum;  } }

出票机类 TicketMachine
 
   
 
   

package bank.demo;
public class TicketMachine {
 //这里定义出票机器,
 //注意机器只有一台,但有3中票;
 //所以要设计为单例模式; 
 private TicketMessage commonClient=new TicketMessage();
 private TicketMessage quickClient=new TicketMessage();
 private TicketMessage vipClient=new TicketMessage();
 public TicketMessage getCommonClient() {
  return commonClient;
 }
 public TicketMessage getQuictClient() {
  return quickClient;
 }
 public TicketMessage getVipClient() {
  return vipClient;
 }
 private TicketMachine(){};
 public static final TicketMachine getInstance=new TicketMachine();//单例设计 模式
 
}

银行窗口, WindowServices
 
   

 
   
package bank.demo;
import java.util.Random;
import java.util.concurrent.Executors;
public class WindowServices {
 //设计服务窗口,有普通窗口,快速窗口,Vip窗口;这里可以用到java1.5新特性,Enum;
 //窗口有叫好,服务功能;
 private Windows windowID=Windows.COMMON;
 private int num=1;
 
 public void setWindowID(Windows windowID) {
  this.windowID = windowID;
 }
 public void setNum(int num) {
  this.num = num;
 }
 //开始;
 public void start(){
  Executors.newSingleThreadExecutor().execute(
   new Runnable() {
   //run方法里要执行叫号和服务代码;
   public void run() {
    while(true){
     switch(windowID){
      case COMMON:
       commonserver();
       break;
      case QUICK:
       quickserver();
       break;
      case VIP:
       vipserver();
       break;
       
     }
    }
   }
  });
  
 }
 public void commonserver(){
  Integer serNum=TicketMachine.getInstance.getCommonClient().serviceTicket();
  System.out.println("第"+num+"号"+windowID+"窗口等待客户");
  if(serNum!=null){
   long startTime=System.currentTimeMillis();
   try {
    Thread.sleep((new Random().nextInt(10)+1)*1000);
   } catch (InterruptedException e) {e.printStackTrace();}
   System.out.println("第"+num+"号"+windowID+"窗口正在为"+serNum+"号普通客户办理业务");
   long endTime=System.currentTimeMillis();
   System.out.println("第"+serNum+"号普通客户在"+num+"号"+windowID+"窗口办理结束,用时"+(endTime-startTime)/1000+"秒");
  }else{
   System.out.println("窗口空闲等待1秒");
   try {
    Thread.sleep(1000);
   } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
  }
 }
 public void quickserver(){
  num=5;
  Integer serNum=TicketMachine.getInstance.getQuictClient().serviceTicket();
  System.out.println("第"+num+"号快速窗口等待客户");
  if(serNum!=null){
   long startTime=System.currentTimeMillis();
   try {
    Thread.sleep(new Random().nextInt(3)*1000);
   } catch (InterruptedException e) {e.printStackTrace();}
   System.out.println("快速窗口正在为"+serNum+"号快速客户办理业务");
   long endTime=System.currentTimeMillis();
   System.out.println("第"+serNum+"号快速客户在"+num+"号"+windowID+"窗口办理结束,用时"+(endTime-startTime)/1000+"秒");
  }else{
   System.out.println("快速窗口空闲");
   commonserver();
  }
 }
 public void vipserver(){
  num=6;
  Integer serNum=TicketMachine.getInstance.getVipClient().serviceTicket();
  System.out.println("第"+num+"号VIP窗口等待客户");
  if(serNum!=null){
   long startTime=System.currentTimeMillis();
   try {
    Thread.sleep(new Random().nextInt(10)*1000);
   } catch (InterruptedException e) {e.printStackTrace();}
   System.out.println("VIP窗口正在为"+serNum+"号VIP客户办理业务");
   long endTime=System.currentTimeMillis();
   System.out.println("第"+serNum+"号VIP客户在"+num+"号"+windowID+"窗口办理结束,用时"+(endTime-startTime)/1000+"秒");
  }else{
   System.out.println("VIP窗口空闲");
   commonserver();
  }
 }
}



 

main函数
 
   
 
   

package bank.demo;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class Main {
 public static void main(String[] args) {
  for(int i=1;i<5;i++){
   WindowServices wn=new WindowServices();
   wn.setNum(i);
   wn.start();
  }
  //创建快速窗口
  WindowServices qw=new WindowServices();
  qw.setWindowID(Windows.QUICK);
  qw.start();
  //创建VIP窗口;
  WindowServices vw=new WindowServices();
  vw.setWindowID(Windows.VIP);
  vw.start();
  Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
   new Runnable() {
    public void run() {
     System.out.println("普通客户取票");
     Integer num=TicketMachine.getInstance.getCommonClient().getTicket();
     System.out.println("第"+num+"号客户在等待");
    }
   },
   0, 
   1, 
   TimeUnit.SECONDS);
  
  Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
    new Runnable() {
     public void run() {
      System.out.println("快速客户取票");
      Integer num=TicketMachine.getInstance.getQuictClient().getTicket();
      System.out.println("第"+num+"号快速客户在等待");
     }
    },
    0, 
    2, 
    TimeUnit.SECONDS);
  Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
    new Runnable() {
     public void run() {
      System.out.println("VIP客户取票");
      Integer num=TicketMachine.getInstance.getVipClient().getTicket();
      System.out.println("第"+num+"号VIP客户在等待");
     }
    },
    0, 
    6, 
    TimeUnit.SECONDS);
 }
}

 
   
窗口类型枚举;
 
   
 
   

package bank.demo;
public enum Windows {
 COMMON,QUICK,VIP;
 public String toString(){
  switch(this){
  case COMMON:
   return "普通";
  case QUICK:
   return "快速";
  case VIP:
   return "VIP";
   
  }
  return null;
 }
}

完毕;
测试结果:
......
第1号普通窗口正在为2号普通客户办理业务
第2号普通客户在1号普通窗口办理结束,用时1秒
第1号普通窗口等待客户
窗口空闲等待1秒
快速窗口正在为1号快速客户办理业务
第1号快速客户在5号快速窗口办理结束,用时2秒
第5号快速窗口等待客户
普通客户取票
第4号客户在等待
第4号普通窗口正在为3号普通客户办理业务
第3号普通客户在4号普通窗口办理结束,用时1秒
第4号普通窗口等待客户
第3号普通窗口等待客户
窗口空闲等待1秒
第1号普通窗口等待客户
快速窗口正在为2号快速客户办理业务
第2号快速客户在5号快速窗口办理结束,用时1秒
......
 

NumberManager和NumberMachine类

NumberManager类 定义一个用于存储上一个客户号码的成员变量和用于存储所有等待服务的客户号码的队列集合。 定义一个产生新号码的方法和获取马上要为之服务的号码的方法,这两个方法被不同的线程操作了相同的数据,所以,要进行同步。 NumberMachine类 定义三个成员变量分别指向三个NumberManager对象,分别表示普通、快速和VIP客户的号码管理器,定义三个对应的方法来返回这三个NumberManager对象。 将NumberMachine类设计成单例。

 

ServiceWindow与CustomerType枚举类 

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

MainClass类与Constants类

MainClass类 用for循环创建出4个普通窗口,再创建出1个快速窗口和一个VIP窗口。 接着再创建三个定时器,分别定时去创建新的普通客户号码、新的快速客户号码、新的VIP客户号码。 Constants类 定义三个常量:MAX_SERVICE_TIME、MIN_SERVICE_TIME、COMMON_CUSTOMER_INTERVAL_TIME。



---------------------- android培训java培训、期待与您交流! ----------------------