项目要求
模拟实现银行业务调度系统逻辑,具体需求如下:
1.银行内有6个业务窗口,1 - 4号窗口为普通窗口,5号窗口为快速窗口,6号窗口为VIP窗口。
2 .有三种对应类型的客户:VIP客户,普通客户,快速客户(办理如交水电费、电话费之类业务的客户)。
3.异步随机生成各种类型的客户,生成各类型用户的概率比例为:
VIP客户 :普通客户 :快速客户 = 1 :6 :3。
4 .客户办理业务所需时间有最大值和最小值,在该范围内随机设定每个VIP客户以及普通客户办理业务所需的时间,快速客户办理业务所需时间为最小值(提示:办理业务的过程可通过线程Sleep的方式模拟)。
5 .各类型客户在其对应窗口按顺序依次办理业务。
6.当VIP(6号)窗口和快速业务(5号)窗口没有客户等待办理业务的时候,这两个窗口可以处理普通客户的业务,而一旦有对应的客户等待办理业务的时候,则优先处理对应客户的业务。
7. 随机生成客户时间间隔以及业务办理时间最大值和最小值自定,可以设置。
8. 不要求实现GUI,只考虑系统逻辑实现,可通过Log方式展现程序运行结果。
思路
经分析,本题除了主函数类之外主要的类还有以下几个:
1.号码管理器类
定义集合存储号码,号码就相当于顾客。同时内部应存在增加和删除号码的方法,来了顾客增加号码,服务完毕删除号码。
2.号码机器类
由于有三类客户,普通,快速和vip,每类客户的号码编排都是完全独立的,需要建立三个不同的号码管理器类,各自管理自己的用户排队号码。这三个号码管理器对象统一由一个号码机器进行管理,所以,他需要设计成单利模式。
3.服务窗口类
各类型客户在其对应窗口按顺序依次办理业务,窗口依次叫号,即窗口每次需要利用号码管理器获取当前要被服务的号码,叫号成功即删除该号码。定义三类窗口的服务方法,普通窗口没有客户时等待1秒再次获取客户,快速和vip窗口没有顾客就获取普通顾客,调用普通窗口的服务方法。
代码实现
客户类型类
//建立客户类型类,分为三种类型,是一个枚举类
public enum CustomerType {
COMMON,QUICK,VIP;
//定义toString方法,返回值是String类型,使程序输出对应的中文客户类型
public String toString(){
String name=null;
switch(this){
case COMMON:
name="普通";
break;
case QUICK:
name="快速";
break;
case VIP:
name=name();
break;
}
return name;
}
}
号码管理器类
/*
* 建立号码管理器类,建立集合管理号码元素,管理器有两个功能,客户来了产生新的号码,窗口叫号时将要被服务的号码返回给窗口,
* 并从集合中出去已被服务的客户号码
*/
public class NumberManager {
private int lastNumber=0;
private List<Integer> queue=new ArrayList<Integer>();//定义集合记录客户号码,便于增删
//定义增加客户资料的方法,增加和取出方法操作同一个数据,需要同步
public synchronized Integer creatNumber(){
queue.add(++lastNumber);//添加对象到客户集合
return lastNumber;
}
//定义叫号方法,即从集合中取出对象
public synchronized Integer fachNumber(){
if(queue.size()>0){
return (Integer)queue.remove(0);//当集合不为空时,窗口叫号会从等待客户号码最靠前的一个开始叫,获得服务资格之后,删除号码
}
else{
return null;
}
}
}
号码机器类
/*
* 建立银行的排号机器类,所有客户都操作同一台机器,属于单例模式,排号机器类中有三个对象,即普通,快速,vip对象
* 每个对象都具有各自的客户数量属性,即有具有各自的号码管理器
*/
public class NumberMachine {
//建立单利设计模式
private NumberMachine(){};
private final static NumberMachine instance=new NumberMachine();
public static NumberMachine getInstance(){
return instance;
}
//创建三个客户类型所对应的号码管理器类
private NumberManager commonManager=new NumberManager();
private NumberManager quickManager=new NumberManager();
private NumberManager vipManager=new NumberManager();
//建立获取三种号码管理器对象的方法
public NumberManager getCommonManager(){
return commonManager;
}
public NumberManager getQuickManager(){
return quickManager;
}
public NumberManager getVipManager(){
return vipManager;
}
}
时间类
//建立时间类,定义生成客户时间间隔以及业务办理时间最大值和最小值,自成一类便于修改设置
public class Time {
//三个时间是被几个类所共享的数据,设置成静态数据
//定义最大服务时间
public static int MAX_SERVICE_TIME=10000;
//定义最小服务时间
public static int MIN_SERVICE_TIME=1000;
//定义产生普通客户的时间间隔,按比例可以得到快速和vip客户产生间隔
public static int COMMON_CUSTOMER_INTERVAL_TIME=1;
}
服务窗口类
/*
* 定义窗口服务类,窗口类有服务方法,每个各户类型具有不同的服务方法,故需要定义三个不同的方法,
* 普通窗口的服务流程为:
* 获取任务--获取成功则开始处理任务(获取客户号码并从号码管理器中移除该客户)--一段时间后任务处理完成--获取下个任务
* 获取任务--没有客户,获取失败--等待一定时间,重新获取
* 快速和vip窗口情况类似:
* 获取任务--获取成功则开始处理任务(获取客户号码并从号码管理器中移除该客户)--一段时间后任务处理完成--获取下个任务
* 获取任务--没有对应客户,获取失败--获取普通客户任务
*/
public class Window {
//定义窗口的类型(即为客户类型)和号码
private CustomerType type=CustomerType.COMMON;//初始化类型为普通客户类
private int number=1;//初始化窗口号码为1号窗口
//获取窗口类型
public CustomerType getType(){
return type;
}
public void setType(CustomerType type){
this.type=type;
}
//获取窗口号码
public int getNumber(){
return number;
}
//传入号码参数
public void setNumber(int number){
this.number=number;
}
//定义窗口的启动方法,根据窗口类型的不同,调用对应类型窗口的服务方法
public void start(){
Executors.newSingleThreadExecutor().execute(
new Runnable(){
public void run(){
while(true){
switch(type){
case COMMON:
commonService();
break;
case QUICK:
quickService();
break;
case VIP:
vipService();
break;
}
}
}
}
);
}
//定义普通窗口的服务方法
private void commonService(){
System.out.println("第"+number+"号"+type+"窗口开始获取任务");
//调用普通客户号码管理类的叫号方法获取要服务客户的号码
Integer serviceNumber=NumberMachine.getInstance().getCommonManager().fachNumber();
if(serviceNumber!=null){
System.out.println("第"+number+"号"+type+"窗口开始为第"+serviceNumber+"号普通客户服务");
//随机产生一段服务时间
int serviceTime=new Random().nextInt(Time.MAX_SERVICE_TIME - Time.MIN_SERVICE_TIME)+Time.MIN_SERVICE_TIME;
try {
Thread.sleep(serviceTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("第"+number+"号"+type+"窗口完成为第"+serviceNumber+"号普通客户的服务,用时"+serviceTime/1000+"秒");
}
else{
//当没有客户等待时,窗口休息一秒钟
System.out.println("第"+number+"号"+type+"窗口没有取到普通任务,空闲一秒");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//定义快速窗口服务方法
private void quickService(){
System.out.println("第"+number+"号"+type+"窗口开始获取任务");
//调用快速客户号码管理类的叫号方法获取要服务客户的号码
Integer serviceNumber=NumberMachine.getInstance().getQuickManager().fachNumber();
if(serviceNumber!=null){
System.out.println("第"+number+"号"+type+"窗口开始为第"+serviceNumber+"号快速客户服务");
//快速客户的服务时间是最小服务时间
int serviceTime= Time.MIN_SERVICE_TIME;
try {
Thread.sleep(serviceTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("第"+number+"号"+type+"窗口完成为第"+serviceNumber+"号快速客户的服务,用时"+serviceTime/1000+"秒");
}
else{
//当没有快速客户等待时,快速窗口为普通客户服务
System.out.println("第"+number+"号"+type+"窗口没有取到快速任务");
commonService();
}
}
//定义vip窗口服务方法
private void vipService(){
System.out.println("第"+number+"号"+type+"窗口开始获取任务");
//调用vip客户号码管理类的叫号方法获取要服务客户的号码
Integer serviceNumber=NumberMachine.getInstance().getVipManager().fachNumber();
if(serviceNumber!=null){
System.out.println("第"+number+"号"+type+"窗口开始为第"+serviceNumber+"号vip客户服务");
//随机产生一段服务时间
int serviceTime=new Random().nextInt(Time.MAX_SERVICE_TIME - Time.MIN_SERVICE_TIME)+Time.MIN_SERVICE_TIME;
try {
Thread.sleep(serviceTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("第"+number+"号"+type+"窗口完成为第"+serviceNumber+"号vip客户的服务,用时"+serviceTime/1000+"秒");
}
else{
//当没有vip客户等待时,vip窗口为普通客户服务
System.out.println("第"+number+"号"+type+"窗口没有取到vip任务");
commonService();
}
}
}
主函数类
/*
* 建立主类,创建六个窗口对象并运行,窗口对象具有类型和号码属性,同时调用号码管理器对象生成客户
*/
public class MainClass {
public static void main(String[] args) {
//创建4个普通窗口对象并运行
for(int x=1;x<5;x++){
Window commonWindow=new Window();
commonWindow.setNumber(x);
commonWindow.start();
}
//创建一个快速窗口并运行
Window quickWindow = new Window();
quickWindow.setType(CustomerType.QUICK);
quickWindow.start();
//创建一个vip窗口并运行
Window vipWindow = new Window();
vipWindow.setType(CustomerType.VIP);
vipWindow.start();
//普通客户拿号
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
new Runnable(){
public void run(){
Integer serviceNumber=NumberMachine.getInstance().getCommonManager().creatNumber();
System.out.println("第"+serviceNumber+"号普通客户正在等待服务");}
},
0,
Time.COMMON_CUSTOMER_INTERVAL_TIME,
TimeUnit.SECONDS);
//快速客户拿号
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
new Runnable(){
public void run(){
Integer serviceNumber=NumberMachine.getInstance().getQuickManager().creatNumber();
System.out.println("第"+serviceNumber+"号快速客户正在等待服务");}
},
0,
Time.COMMON_CUSTOMER_INTERVAL_TIME*2,
TimeUnit.SECONDS);
//vip客户拿号
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
new Runnable(){
public void run(){
Integer serviceNumber=NumberMachine.getInstance().getVipManager().creatNumber();
System.out.println("第"+serviceNumber+"号vip客户正在等待服务");}
},
0,
Time.COMMON_CUSTOMER_INTERVAL_TIME*6,
TimeUnit.SECONDS);
}
}
学习感悟
经过昨天交通灯类的学习,学习这个银行业务调度系统简单多了,特别是明了了谁拥有数据谁就定义操作它的方法的面向对象思想之后,可以很快地确定题目所需的类及其所含方法。看张老师的代码,每天都有新收获。比如将时间独立成类,便于修改,共享数据可以设置成静态等,虽然道理我懂,但是真在写代码的时候我是想不到的。还是对代码的熟练度不够,还得努力学习啊。