看了张孝祥老师的讲解,对比自己完成的程序发现除了版本1红色字体标出的地方,还存在以下几点需要改进的地方:
(1) 客户和服务的类型应该使用枚举类型,而自己是用数字1 2 3标记的,方法有点low。这里使用枚举类型更适合,能够限制可取的值只有事先指定的类型。因此在版本2中增加了类ServType类。为了后面的代码重用,这里需要重写它的toString方法。
package edu.uestc.bank2;
public enum ServType {
COMMON, EXPRESS, VIP;
public String toString() {
String name = null;
switch(this) {
case COMMON:
name = "普通";
break;
case EXPRESS:
name = "快速";
break;
case VIP:
name = name();
}
return name;
}
}
(2) 系统中用到的常量最好定义在专门的类中,增加了类Constants。
package edu.uestc.bank2;
public class Constants {
public static int maxServTime = 10000;
public static int minservTime = 1000;
}
系统中的其他类:
(1) NumberManager可以保持不变
(2) NumberMachine类设计成单例类。
package edu.uestc.bank2;
public class NumberMachine {
//因为系统中只有一个号码机器,故设计成单例类
private NumberManager commomManager = new NumberManager();
private NumberManager expressManager = new NumberManager();
private NumberManager vipManager = new NumberManager();
private static NumberMachine instance;
private NumberMachine() {}
//获取该类的实例
public static NumberMachine getInstance() {
if(instance == null) {
instance = new NumberMachine();
}
return instance;
}
public NumberManager getCommonManager() {
return commomManager;
}
public NumberManager getExpressManager() {
return expressManager;
}
public NumberManager getVipManager() {
return vipManager;
}
}
(3) ServiceWindow,因为要使用线程池所以讲该类改为实现Runnable接口的类而不是继承自Thread的类,另外还有commonService代码重用的改进。
package edu.uestc.bank2;
import java.util.Random;
public class ServiceWindow implements Runnable{
private int windowId;
private ServType windowType = ServType.COMMON;
public ServiceWindow(int windowId, ServType windowType) {
this.windowId = windowId;
this.windowType = windowType;
}
public void run() {
while(true) {
switch(windowType) {
case COMMON:
commonService();
break;
case EXPRESS:
expressService();
break;
case VIP:
vipService();
break;
}
}
}
public void commonService() {
ServType customerType = ServType.COMMON;
System.out.println(windowId + "号" + windowType + "窗口正在取" + customerType + "号");
int customerNum = NumberMachine.getInstance().getCommonManager().fetchNumber();
if(customerNum == -1) {
System.out.println(windowId + "号" + windowType + "窗口没有取到" + customerType +"号,休息1秒");
try {
Thread.sleep(1000);
} catch(InterruptedException e) {
e.printStackTrace();
}
}
else {
System.out.println(windowId + "号" + windowType + "窗口开始为" + customerNum + "号" + customerType + "客户服务");
long ramServTime = (new Random()).nextInt(Constants.maxServTime - Constants.minservTime) + 1 + Constants.minservTime;
try {
Thread.sleep(ramServTime);
} catch(InterruptedException e) {
e.printStackTrace();
}
System.out.println(windowId + "号" + windowType + "窗口为" + customerNum + "号" + customerType + "客户服务完毕,服务时间为" + ramServTime/1000 + "秒");
}
}
public void expressService() {
ServType customerType = ServType.EXPRESS;
System.out.println(windowId + "号" + windowType + "窗口正在取" + customerType + "号");
int customerNum = NumberMachine.getInstance().getExpressManager().fetchNumber();
if(customerNum == -1) {
System.out.println(windowId + "号" + windowType + "窗口没有取到" + customerType +"号");
customerType = ServType.COMMON;
commonService(); // 代码重用
}
else {
System.out.println(windowId + "号" + windowType + "窗口开始为" + customerNum + "号" + customerType + "客户服务");
try {
Thread.sleep(Constants.minservTime);
} catch(InterruptedException e) {
e.printStackTrace();
}
System.out.println(windowId + "号" + windowType + "窗口为" + customerNum + "号" + customerType + "客户服务完毕,服务时间为" + Constants.minservTime/1000 + "秒");
}
}
public void vipService() {
ServType customerType = ServType.VIP;
System.out.println(windowId + "号" + windowType + "窗口正在取" + customerType + "号");
int customerNum = NumberMachine.getInstance().getVipManager().fetchNumber();
if(customerNum == -1) {
System.out.println(windowId + "号" + windowType + "窗口没有取到" + customerType +"号");
customerType = ServType.COMMON;
commonService(); //代码重用
}
else {
System.out.println(windowId + "号" + windowType + "窗口开始为" + customerNum + "号" + customerType + "客户服务");
long ramServTime = (new Random()).nextInt(Constants.maxServTime - Constants.minservTime) + 1 + Constants.minservTime;
try {
Thread.sleep(ramServTime);
} catch(InterruptedException e) {
e.printStackTrace();
}
System.out.println(windowId + "号" + windowType + "窗口为" + customerNum + "号" + customerType + "客户服务完毕,服务时间为" + ramServTime/1000 + "秒");
}
}
}
(4) MainClass ,采用了线程池的方法启动服务窗口。产生新号码也在main函数中实现,采用调度线程池的方式实现异步随机产生新号码。
package edu.uestc.bank2;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class MainClass {
public static void main(String[] args) {
//服务线程池
ExecutorService pool = Executors.newFixedThreadPool(6);
for(int i = 1; i < 5; i++) {
pool.submit(new ServiceWindow(i,ServType.COMMON));
}
pool.submit(new ServiceWindow(5, ServType.EXPRESS));
pool.submit(new ServiceWindow(6, ServType.VIP));
//产生普通号的调度线程池
ScheduledExecutorService comPool = Executors.newScheduledThreadPool(1);
comPool.scheduleAtFixedRate(
new Runnable() {
public void run() {
NumberMachine.getInstance().getCommonManager().generateNumber();
}
},
0,
1,
TimeUnit.SECONDS);
//产生快速号的调度线程池
ScheduledExecutorService expPool = Executors.newScheduledThreadPool(1);
expPool.scheduleAtFixedRate(
new Runnable() {
public void run() {
NumberMachine.getInstance().getExpressManager().generateNumber();
}
},
0,
2,
TimeUnit.SECONDS);
//产生Vip号的调度线程池
ScheduledExecutorService vipPool = Executors.newScheduledThreadPool(1);
vipPool.scheduleAtFixedRate(
new Runnable() {
public void run() {
NumberMachine.getInstance().getVipManager().generateNumber();
}
},
0,
6,
TimeUnit.SECONDS);
}
}
完成。