------- android培训、java培训、期待与您交流! ----------
今天学习了张老师制作银行业务调度系统项目的视频,刚看题的时候,感觉却是一团乱麻,虽然我在银行工作过,也很清楚这个排号叫号过程是什么样子的,对其中的过程也很了解,但是让我把这些过程转换为代码确实很难。其中有些东西有些思路,比如排号需要一个排号机可以设计为单例,里面有三个为不同类型客户排号取号的功能等等,但是更多的却是知道过程而不知道如何用代码表示,而在看完张老师视频之后,发现老师所讲的内容自己都是学过的,基本没有新东西,但是如果自己做这个题目,自己只能写出其中一些微不足道的代码来,以后要在这方面多加练习,等到在黑马毕业后,也可以轻松拿到7K+的月薪。
下面来写我通过学习张老师视频的一些总结。
一、先看一下需求:
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、首先,由于有三类客户,所以有三个号码管理器对象,每个对象中不断地产生号码,也就是产生客户,并且这个对象还应对外提供获取这些号码(客户)的方法,也就是为了后面的服务窗口提供叫号服务。由于产生新号码和获取号码的方法要被不同线程操作其中的相同数据,因此要进行同步处理,只需加synchronized即可,代码如下:
public class NumberManager {
private int lastNumber = 1;
private List<Integer> queueNumber = newArrayList<Integer>();//提供存储客户的容器
public synchronized IntegergenerateNewManager(){
queueNumber.add(lastNumber);
return lastNumber++;
}
public synchronized IntegerfetchServiceNumber(){
//由于取号时集合中可能为空,因此需要判断,并且返回值用Integer而不是int
Integernumber = null;
if(queueNumber.size()>0)
return queueNumber.remove(0);
return number;
}
}
2、需要有一个产生号码的机器,这个机器可以为三个不同类型客户进行排号取号叫号服务,因此里面需要有三个号码管理器对象,并且由于这个机器是唯一的,因此需要设计成单例。
public class NumberMachine {
private NumberManager commonManager = new NumberManager();
private NumberManager expressManager = new NumberManager();
private NumberManager vipManager = new NumberManager();
public NumberManagergetCommonManager() {
return commonManager;
}
public NumberManagergetExpressManager() {
return expressManager;
}
public NumberManagergetVipManager() {
return vipManager;
}
private NumberMachine(){}
public static NumberMachinegetInstance(){
return instance;
}
private static NumberMachine instance = new NumberMachine();
}
3、客户的类型有三种,因此设计成枚举会很方便,其中三个成员分别表示三种类型的客户。而由于后面为了方便阅读,需要用到客户类型的toString方法,因此重写该方法。代码如下:
public enum CustomerType {
COMMEN,EXPRESS,VIP;
public String toString(){
switch(this){
case COMMEN:
return"普通";
case EXPRESS:
return"快速";
case VIP:
return"VIP";
}
return null;
}
}
4、服务窗口类的建立:因为有三种不同类型的窗口,建立成员变量窗口号码和窗口类型,并提供set方法以供后面创建不同窗口的时候设置。在类中定义一个start方法,其中启动一个线程,该线程根据窗口类型以及窗口号码的不同分别循环(用while(true)实现)调用其中三个针对不同客户所写的不同方法。代码如下:
public class ServiceWindow {
//默认普通窗口,通过下面set方法可以改变窗口类型即号码。
private CustomerType type = CustomerType.COMMEN;
private int windowID=1;
public void setType(CustomerType type){
this.type = type;
}
public void setWindowID(int windowID) {
this.windowID = windowID;
}
public void start(){
Executors.newSingleThreadExecutor().execute(new Runnable() {
public void run() {
while(true){//循环调用该线程
switch(type){
case COMMEN:
commonService();
break;
case EXPRESS:
expressService();
break;
case VIP:
vipService();
}
}
}
});
}
private void commonService() {
StringwindowName="第"+windowID+"号"+type+"窗口";
System.out.println(windowName+"正在获取任务");
Integernumber = NumberMachine.getInstance().getCommonManager().fetchServiceNumber();
if(number!=null){
System.out.println(windowName+"为第"+number+"个普通客户服务");
long beginTime = System.currentTimeMillis();
int maxRand = Constants.MAX_SERVICE_TIME-Constants.MIN_SERVICE_TIME;
long serviceTime=newRandom().nextInt(maxRand)+1+Constants.MIN_SERVICE_TIME;
try {
Thread.sleep(serviceTime);
}catch (InterruptedException e) {
e.printStackTrace();
}
long time = System.currentTimeMillis()-beginTime;
System.out.println(windowName+"为第"+number+"个普通客户完成服务,耗时"+time/1000+"秒");
}
else{
System.out.println(windowName+"没有取到任务,先休息一秒");
try {
Thread.sleep(1000);
}catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void expressService() {
StringwindowName="第"+windowID+"号"+type+"窗口";
System.out.println(windowName+"正在获取任务");
Integernumber = NumberMachine.getInstance().getExpressManager().fetchServiceNumber();
if(number!=null){
System.out.println(windowName+"为第"+number+"个"+type+"客户服务");
long beginTime = System.currentTimeMillis();
//int maxRand =Constants.MAX_SERVICE_TIME-Constants.MIN_SERVICE_TIME;
//long serviceTime=newRandom().nextInt(maxRand)+1+Constants.MIN_SERVICE_TIME;
try {
Thread.sleep(Constants.MIN_SERVICE_TIME);
}catch (InterruptedException e) {
e.printStackTrace();
}
long time = System.currentTimeMillis()-beginTime;
System.out.println(windowName+"为第"+number+"个"+type+"客户完成服务,耗时"+time/1000+"秒");
}
else{
System.out.println(windowName+"没有取到任务,先休息一秒");
commonService();
}
}
private void vipService() {
StringwindowName="第"+windowID+"号"+type+"窗口";
System.out.println(windowName+"正在获取任务");
Integernumber = NumberMachine.getInstance().getVipManager().fetchServiceNumber();
if(number!=null){
System.out.println(windowName+"为第"+number+"个"+type+"客户服务");
long beginTime = System.currentTimeMillis();
int maxRand = Constants.MAX_SERVICE_TIME-Constants.MIN_SERVICE_TIME;
long serviceTime=newRandom().nextInt(maxRand)+1+Constants.MIN_SERVICE_TIME;
try {
Thread.sleep(serviceTime);
}catch (InterruptedException e) {
e.printStackTrace();
}
long time = System.currentTimeMillis()-beginTime;
System.out.println(windowName+"为第"+number+"个"+type+"客户完成服务,耗时"+time/1000+"秒");
}
else{
System.out.println(windowName+"没有取到任务,先休息一秒");
commonService();
}
}
}
5、主函数的建立:主函数创建出来4个普通窗口,一个VIP窗口,一个快速窗口,并且启动其中的start方法使其中的线程方法运作起来。再通过定时器来按照1:6:3的比例创建不同客户。代码如下:
public class MainClass {
public static void main(String[] args) {
for(int i=1;i<5;i++){
ServiceWindowcommenWindow = new ServiceWindow();
commenWindow.setWindowID(i);
commenWindow.start();
}
ServiceWindowexpressWindow = new ServiceWindow();
expressWindow.setType(CustomerType.EXPRESS);
expressWindow.start();
ServiceWindowvipWindow = new ServiceWindow();
vipWindow.setType(CustomerType.VIP);
vipWindow.start();
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
new Runnable() {
public void run() {
Integernumber =NumberMachine.getInstance().getCommonManager().generateNewManager();
System.out.println("第"+number+"号普通客户等待服务");
}
},
0,
Constants.COMMON_CUSTOMER_INTERVAL,
TimeUnit.SECONDS);
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
new Runnable() {
public void run() {
Integernumber =NumberMachine.getInstance().getVipManager().generateNewManager();
System.out.println("第"+number+"号VIP客户等待服务");
}
},
0,
Constants.COMMON_CUSTOMER_INTERVAL*6,
TimeUnit.SECONDS);
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
new Runnable() {
public void run() {
Integernumber =NumberMachine.getInstance().getExpressManager().generateNewManager();
System.out.println("第"+number+"号快速客户等待服务");
}
},
0,
Constants.COMMON_CUSTOMER_INTERVAL*3,
TimeUnit.SECONDS);
}
}
6、把前面用到的一些常量数据定义到一个单独的类中,方便调用以及阅读代码如下:
public class Constants {
public static int MAX_SERVICE_TIME=10000;
public static int MIN_SERVICE_TIME=1000;
public static int COMMON_CUSTOMER_INTERVAL = 1;
}