本例学习总结:本案例中用到了单例设计模式,要明白客户号与窗口叫号的产生方法,明白其中的逻辑关系。面向对象方法的运用,比如,窗口有类型属性是普通还是快速还是vip,有号这个属性,窗口是几号窗口,针对不同窗口再设计该窗口的处理方法,这样逻辑就清楚了。
需求分析:1.银行有三种业务窗口,分别为普通,快速,vip窗口,分别班里对应客户的业务,但是,快速和vip窗口可以办理普通客户业务。2,有三种类型客户,普通,快速,vip客户。3,模拟客户出现的概率比为6:3:1。4,普通和vip客户办理业务时间用随机数表示,快速客户业务办理时间用最小时间表示。
设计实现:三种类型客户办理业务时要有客户号,需要生成三种客户号,三种类型客户号有一个出客户号机器产生,所以,先设计一个产生客户号的类
import java.util.ArrayList;
import java.util.List;
public class NumberManager {
private int lastNumber = 1;
//为了取出排队号码方便,采用ArrayList
private List<Integer> queueNumber = new ArrayList<Integer>();
//由于取出和产生号码共享数据,要考虑同步问题,如果函数返回类型为int,由于在判断取出的号码是否为空,返回null时会出错,
//所以用Integer作为返回类型,使用java的自动装箱特性
public synchronized Integer generateNewNumber() {
queueNumber.add(lastNumber);
return lastNumber++;
}
public synchronized Integer fetchNumber() {
if (queueNumber.size() > 0) {
return queueNumber.remove(0);
}
else {
return null;
}
}
}
然后,对于三种类型客户,设计一个类,管理产生的客户号如下:
public class NumberMachine {
/*
* 单例设计模式
*/
private NumberMachine(){}
private static NumberMachine instance = new NumberMachine();
public static NumberMachine getInstance() {
return instance;
}
private NumberManager commonManager = new NumberManager();
private NumberManager expressManager = new NumberManager();
private NumberManager vipManager = new NumberManager();
public NumberManager getCommonManager() {
return commonManager;
}
public NumberManager getExpressManager() {
return expressManager;
}
public NumberManager getVipManager() {
return vipManager;
}
}
用到了单例设计模式,这是考虑到三种类型客户号有一个客户号机产生。
然后设计办理客户业务的窗口类,有属性:窗口类型和窗口号,在start方法中完成业务办理,分三种类型处理
import java.util.Random;
import java.util.concurrent.Executors;
public class ServiceWindow {
private int number = 1;
private CustomerType type = CustomerType.COMMON;
public void setNumber(int number) {
this.number = number;
}
public void setType(CustomerType type) {
this.type = type;
}
public CustomerType getType() {
return type;
}
public void start() {
Executors.newSingleThreadExecutor().execute(new Runnable() {
@Override
public void run() {
while (true) {
switch (type) {
case COMMON:
commonService();
break;
case EXPRESS:
expressService();
break;
case VIP:
vipService();
break;
}
}
}
});
}
以普通业务办理为例:下面是commonService()方法的代码:
private void commonService() {
String windowName = "第" + number +"号" + type + "窗口";
System.out.println(windowName + "开始获取普通任务");
//获取客户服务号
Integer serviceNumber = NumberMachine.getInstance().getCommonManager().fetchNumber();
//如果服务号不为空就办理业务
if (serviceNumber != null) {
System.out.println(windowName + "开始为第" + serviceNumber + "号客户服务");
//设计一个在最大值和最新值之间的随机数模拟业务办理时间
int maxRand = Constants.MAX_SEVICE_TIME - Constants.MIN_SEVICE_TIME;
int serviceTime = new Random().nextInt(maxRand) + 1 + Constants.MIN_SEVICE_TIME;
try {
Thread.sleep(serviceTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(windowName + "完成为第" + serviceNumber + "号普通客户服务,总共耗时" + serviceTime/1000 + "秒");
}else {
System.out.println(windowName + "没有取到普通任务,将要空闲一秒");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
最后完成测试用例类:
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
public class Main{
public static void main(String[] args) {
//产生4个普通窗口
for(int i=1;i<5;i++){
ServiceWindow window = new ServiceWindow();
window.setNumber(i);
window.start();
}
//产生1个快速窗口
ServiceWindow expressWindow = new ServiceWindow();
expressWindow.setType(CustomerType.EXPRESS);
expressWindow.start();
//产生1个VIP窗口
ServiceWindow vipWindow = new ServiceWindow();
vipWindow.setType(CustomerType.VIP);
vipWindow.start();
//普通客户拿号
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
new Runnable(){
public void run(){
Integer serviceNumber = NumberMachine.getInstance().getCommonManager().generateNewNumber();
System.out.println("第" + serviceNumber + "号普通客户正在等待服务!");
}
},
0,
Constants.COMMON_CUSTOMER_INTERVAL_TIME,
TimeUnit.SECONDS);
//快速客户拿号
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
new Runnable(){
public void run(){
Integer serviceNumber = NumberMachine.getInstance().getExpressManager().generateNewNumber();
System.out.println("第" + serviceNumber + "号快速客户正在等待服务!");
}
},
0,
Constants.COMMON_CUSTOMER_INTERVAL_TIME * 2,
TimeUnit.SECONDS);
//VIP客户拿号
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
new Runnable(){
public void run(){
Integer serviceNumber = NumberMachine.getInstance().getVipManager().generateNewNumber();
System.out.println("第" + serviceNumber + "号VIP客户正在等待服务!");
}
},
0,
Constants.COMMON_CUSTOMER_INTERVAL_TIME * 6,
TimeUnit.SECONDS);
}
}
其中COMMON_CUSTOMER_INTERVAL_TIME值是1,表明一个普通客户在一秒后出现一个,所以快速客户和vip客户出现的时间就是COMMON_CUSTOMER_INTERVAL_TIME*2和COMMON_CUSTOMER_INTERVAL_TIME*6.