一、需求分析
1、项目需求
模拟银行业务窗口调度系统实现逻辑,需求如下:
(1) 银行内有6个业务窗口,1-4号窗口为普通窗口,5号为快速窗口,6号为VIP窗口。
(2) 有3种业务类型:普通用户,快速用户(如办理水电费,电话费之类的业务),VIP用户。
(3) 异步随机生成各种类型的客户,生成的客户类型比为。
VIP客户:普通用户:快速用户 = 1 : 6 : 3
(4) 客户办理业务所需时间有最大最小值,VIP和普通客户办理时间为最大最小值范围内的随机值,快速客户办理业务的时间为最小值最大最小值自定。
(5) 各类型客户在对应窗口按顺序依次办理业务。
(6) 当VIP窗口和快速窗口没有对应的业务时,可办理普通客户业务,一旦有对应业务,则优先办理对应业务。
(7) 随机生成客户时间间隔自定。
(8) 不需要实现GUI,只考虑逻辑实现,通过Log方式展现程序运行结果。
2、面向对象设计与分析
(1) 首先通过需求,提取类和对象的信息。
VIP客户,普通客户,快速客户 ,是异步随机生成的客户,各客户优先在其对应窗口按顺序依次办理业务。其实每一个客户就是由银行的一个取号机器产生的方式来表示的。所以,要有一个号码管理器对象,让这个对象不断地产生号码,就等于随机的生成了客户。
(2) 由于有三类客户,每类客户的号码编排都是完全独立的,所以,我想到本系统一共要产生三码管理器对象,各自管理一类用户的排队号码。这三个号码管理器对象统一由一个号码机器管理,这个号码机器在整个系统中始终只能有一个,所以,它要被设计成单例。
(3) 各类型客户在其对应窗口按顺序依次办理业务,准确地说,应该是窗口依次叫号。之所以各个窗口知道叫哪一个号,它一定是问的相应的号码管理器,即服务窗口每次找号码管理器获取当前要被服务的号码。
(4) 类图
画图非常有助于理解和分析问题,类图把整个程序结构给清晰的展现,如下:
二、代码设计与编写
1、首先编写设计NumberManager类模拟产生各种类型的客户。
实现功能1:产生客户号码存储到List集合,模拟客户按号排队等待
实现功能2:取出客户号码,即将List集合中的号码移除并返回号码,模拟叫号为客户号码服务
注意事项:定义一个产生新号码的方法和获取马上要为之服务的号码的方法,这两个方法被不同的线程操作了相同的数据,所以,要进行同步。
package com.isoftstone.interviev.bank;
import java.util.ArrayList;
import java.util.List;
public class NumberManager {
private int lastNumber = 1;
private List<Integer> queueNumber = new ArrayList<Integer>();
public synchronized Integer generateNewManager(){
queueNumber.add(lastNumber);
return lastNumber++;
}
public synchronized Integer fetchServiceNumbr(){
Integer nuber = null;
if(queueNumber.size()>0)
nuber = queueNumber.remove(0);
return nuber;
}
}
2、编写设计NumberMachine类
(1)保证对象的唯一性,涉及单例模式, 使用单例设计模式设计此类。
(2)实现功能1:管理产生各种客户类型号码的NumberMachine类实例对象,并提供对公共方法返回这些实例对象
package com.isoftstone.interviev.bank;
import java.util.ArrayList;
import java.util.List;
public class NumberManager {
private int lastNumber = 1;
private List<Integer> queueNumber = new ArrayList<Integer>();
public synchronized Integer generateNewManager(){
queueNumber.add(lastNumber);
return lastNumber++;
}
public synchronized Integer fetchServiceNumbr(){
Integer nuber = null;
if(queueNumber.size()>0)
nuber = queueNumber.remove(0);
return nuber;
}
}
3、编写银行业务服务窗口ServiceWindow类
实现功能1:启动业务窗口,定义不同类型客户的对应的服务流程方法
实现功能2:判断客户类型,并优先办理与窗口对应类型的客户的业务
package com.isoftstone.interviev.bank;
import java.util.Random;
import java.util.concurrent.Executors;
public class ServiceWindow {
private CustomerType type = CustomerType.COMMON;
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 COMMON:
commonService();
break;
case EXPRESS:
expressService();
break;
case VIP:
VIPService();
break;
}
}
}
});
}
private void commonService() {
String windowName = "第"+windowId+"号"+type+"窗口";
Integer servicenumber = NumberMachine.getInstance().getCommonManager().fetchServiceNumbr();
System.out.println(windowName+"正在获取任务");
if(servicenumber != null){
System.out.println(windowName+"为第"+servicenumber+"个"+"普通"+"客户服务");
long geginTime = System.currentTimeMillis();
int maxRand = Constans.MAX_SERVICE_TIME - Constans.MIN_SERVICE_TIME;
long serveTime = new Random().nextInt(maxRand)+1+Constans.MIN_SERVICE_TIME;
try {
Thread.sleep(serveTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
long cosetTime = System.currentTimeMillis()-geginTime;
System.out.println(windowName+"为第"+servicenumber+"个"+"普通"+"客户完成服务,耗时"+serveTime/1000+"秒");
}else{
System.out.println(windowName+"没有取到任务,先休息一秒");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void expressService() {
String windowName = "第"+windowId+"号"+type+"窗口";
Integer servicenumber = NumberMachine.getInstance().getExpressManager().fetchServiceNumbr();
System.out.println(windowName+"正在获取任务");
if(servicenumber != null){
System.out.println(windowName+"为第"+servicenumber+"个"+type+"客户服务");
long geginTime = System.currentTimeMillis();
try {
Thread.sleep(Constans.MIN_SERVICE_TIME);
} catch (InterruptedException e) {
e.printStackTrace();
}
long cosetTime = System.currentTimeMillis()-geginTime;
System.out.println(windowName+"为第"+servicenumber+"个"+type+"客户完成服务,耗时"+cosetTime/1000+"秒");
}else{
System.out.println(windowName+"没有取到任务");
commonService();
}
}
private void VIPService() {
String windowName = "第"+windowId+"号"+type+"窗口";
Integer servicenumber = NumberMachine.getInstance().getVIPManager().fetchServiceNumbr();
System.out.println(windowName+"正在获取任务");
if(servicenumber != null){
System.out.println(windowName+"为第"+servicenumber+"个"+type+"客户服务");
long geginTime = System.currentTimeMillis();
int maxServeTime = Constans.MAX_SERVICE_TIME - Constans.MIN_SERVICE_TIME;
long serveTime = new Random().nextInt(maxServeTime)+1+Constans.MIN_SERVICE_TIME;
try {
Thread.sleep(serveTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
long cosetTime = System.currentTimeMillis()-geginTime;
System.out.println(windowName+"为第"+servicenumber+"个"+type+"客户完成服务,耗时"+cosetTime/1000+"秒");
}else{
System.out.println(windowName+"没有取到任务");
commonService();
}
}
}
4、编写设计客户类型类_使用了具有高安全性的枚举类实现
package com.isoftstone.interviev.bank;
public enum CustomerType {
COMMON,EXPRESS,VIP;
public String toString(){
switch(this){
case COMMON:
return "普通";
case EXPRESS:
return "快速";
case VIP:
return name();
}
return null;
}
}
5、编写设计业务服务时间最值常量Constans类
package com.isoftstone.interviev.bank;
import java.util.concurrent.TimeUnit;
public class Constans {
public static int MAX_SERVICE_TIME = 10000;
public static int MIN_SERVICE_TIME = 1000;
public static int COMMON_CUSTOMER_INTERVAL_TLME = 1;
}
6、编写设计主测试MainClass类
创建各种类型业务窗口实例对象,启动窗口,开始叫号
异步增加不同类型的客户号码
package com.isoftstone.interviev.bank;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class MainClass {
public static void main(String[] args) {
for(int i=1;i<5;i++){
ServiceWindow commonwindow = new ServiceWindow();
commonwindow.setWindowId(i);
commonwindow.start();
}
ServiceWindow expresswindow = new ServiceWindow();
expresswindow.setType(CustomerType.EXPRESS);
expresswindow.start();
ServiceWindow vipwindow = new ServiceWindow();
vipwindow.setType(CustomerType.VIP);
vipwindow.start();
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
new Runnable(){
public void run(){
Integer number = NumberMachine.getInstance().getCommonManager().generateNewManager();
System.out.println(number + "号普通客户等待服务");
}
},
0,
Constans.COMMON_CUSTOMER_INTERVAL_TLME*3,
TimeUnit.SECONDS
);
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
new Runnable(){
public void run(){
Integer number = NumberMachine.getInstance().getExpressManager().generateNewManager();
System.out.println(number + "号快速客户等待服务");
}
},
0,
Constans.COMMON_CUSTOMER_INTERVAL_TLME*2,
TimeUnit.SECONDS
);
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
new Runnable(){
public void run(){
Integer number = NumberMachine.getInstance().getVIPManager().generateNewManager();
System.out.println(number + "号VIP客户等待服务");
}
},
0,
Constans.COMMON_CUSTOMER_INTERVAL_TLME*6,
TimeUnit.SECONDS
);
}
}
三、总结
1、面向对象的一个思维方式:谁拥有数据,谁就对外提供操作这些数据的方法。