銀行業務調度系統
一、需求
1.1、銀行有6個業務窗口,1—4號窗口爲普通窗口,5號窗口爲快速窗口,6號窗口爲VIP窗口。
1.2、有三種對應類型的客戶:普通客戶、快速客戶、VIP客戶。
1.3、異步隨機生成各種類型的客戶,生成各類型用戶比例爲:VIP、快速、普通:1:6:3。
1.4、客戶辦理業務所需時間有最大值和最小值,在該範圍內隨機設定每個VIP客戶以及普通客戶辦理業務所需的時間,快速客戶辦理業務所需時間爲最小值。
1.5、各類型客戶在其對應窗口按順序辦理業務。
1.6、當VIP(6)號窗口和快速業務(5)號窗口沒有客戶等待辦理業務時,這兩個窗口可以處理普通客戶的業務,而一旦有對應的客戶等待辦理業務時,則優先處理對應客戶的業務。
1.7、隨機生成客戶時間間隔以及業務辦理時間最大值和最小值自定,可以設置。
1.8、不要求實現GUI,只考慮系統邏輯實現,可通過log方法展現程序運行結果。
二、需求分析
每一個客戶其實就是由銀行的一個取號機器產生的,所以,我們要定義一個號碼管理器的對象,讓這個對象不斷的產生號碼,就等於隨機生成了客戶。
因爲有三類客戶,每類客戶的號碼編排都是完全獨立的,所以,本系統中要定義三個號碼管理器對象,各自管理一類用戶的排隊號碼。並且定義一個號碼機器管理這三個號碼管理器對象,該號碼機器在整個系統中只能有一個,所以,設計成單例的模式。
客戶得到服務,其實是窗口叫號,所以應該定義一個窗口服務的類,要取號,它問的是相應的號碼管理器,即服務窗口每次找號碼管理器獲取當前要被服務的號碼。
綜上所述:該系統主要產生的類:號碼管理器,號碼機器,服務窗口!類圖如下:
三、編碼實現
號碼管理器:NumberManager類,定義一個List集合用於存儲等待服務的號碼;並且提供產生號碼(即用戶進來取號的動作)的方法;提供取號(即服務窗口要提供服務時獲取號碼的動作)的方法。
代碼如下:
package itheima.interview.bankProject;
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 fetchServiceNumber(){
Integer number = null;
if(queueNumber.size()>0){
number = queueNumber.remove(0);
}
return number;
}
}
號碼機器:NumberMachine類,定義三個號碼管理器,用於管理三種不同客戶的號碼,即:定義三個NumberManager對象;本系統中,號碼機器只能有一個,所以本類設計成單例模式。
代碼如下:
package itheima.interview.bankProject;
public class NumberMachine {
private NumberManager commomManager = new NumberManager();
private NumberManager expressManager = new NumberManager();
private NumberManager vipManager = new NumberManager();
public NumberManager getCommomManager() {
return commomManager;
}
public NumberManager getExpressManager() {
return expressManager;
}
public NumberManager getVipManager() {
return vipManager;
}
private NumberMachine(){}
private static NumberMachine instance = new NumberMachine();
public static NumberMachine getInstance(){
return instance;
}
}
用戶類型:CustomerType枚舉類,系統中有普通、快速、VIP三類客戶,用枚舉類表示更加簡單;重寫toString方法,返回類型的中文名稱,打印的時候更加方便我們的閱讀。
代碼如下:
package itheima.interview.bankProject;
public enum CustomerType {
COMMON,EXPRESS,VIP;
@Override
public String toString(){
switch(this){
case COMMON:
return "普通";
case EXPRESS:
return "快速";
case VIP:
return "VIP";
}
return null;
}
}
服務窗口:ServiceWindow類,定義一個Start方法,內部啓動一個線程,根據服務窗口的類別分別循環調用三個不同的方法爲三種不同的客戶進行服務;定義三個方法分別對三種客戶進行服務,並且打印其中的細節信息。
代碼如下:
package itheima.interview.bankProject;
import java.util.Random;
import java.util.concurrent.Executors;
<span style="white-space:pre"> </span>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(){
@Override
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 number =NumberMachine.getInstance().getCommomManager().fetchServiceNumber();
System.out.println(windowName+"正在獲取任務");
if(number!=null){
System.out.println(windowName+"正在爲第"+number+"個"+"普通"+"客戶服務");
long beginTime = System.currentTimeMillis();
int maxRand = Constants.MAX_SERVICE_TIME-Constants.MIN_SERVICE_TIME;
long serveTime =new Random().nextInt(maxRand)+1+Constants.MIN_SERVICE_TIME;
try {
線程休息,模擬服務所需時間
Thread.sleep(serveTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
long costTime = System.currentTimeMillis()- beginTime;
System.out.println(windowName+"爲第"+number+"個"+"普通"+"客戶完成服務,耗時"+costTime/1000);
}else{
<span style="white-space:pre"> </span>System.out.println(windowName+"沒有取到任務,先休息1秒");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void expressService() {
String windowName = "第"+windowId+"號"+type+"窗口";
Integer number =NumberMachine.getInstance().getExpressManager().fetchServiceNumber();
System.out.println(windowName+"正在獲取任務");
if(number!=null){
System.out.println(windowName+"正在爲第"+number+"個"+type+"客戶服務");
long beginTime = System.currentTimeMillis();
try {
Thread.sleep(Constants.MIN_SERVICE_TIME);
} catch (InterruptedException e) {
e.printStackTrace();
}
long costTime = System.currentTimeMillis()- beginTime;
System.out.println(windowName+"爲第"+number+"個"+type+"客戶完成服務,耗時"+costTime/1000);
}else{
System.out.println(windowName+"沒有取到任務");
commonService();
}
}
private void VIPService() {
String windowName = "第"+windowId+"號"+type+"窗口";
Integer number =NumberMachine.getInstance().getVipManager().fetchServiceNumber();
System.out.println(windowName+"正在獲取任務");
if(number!=null){
System.out.println(windowName+"正在爲第"+number+"個"+type+"客戶服務");
long beginTime = System.currentTimeMillis();
int maxRand = Constants.MAX_SERVICE_TIME-Constants.MIN_SERVICE_TIME;
long serveTime =new Random().nextInt(maxRand)+1+Constants.MIN_SERVICE_TIME;
try {
Thread.sleep(serveTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
long costTime = System.currentTimeMillis()- beginTime;
System.out.println(windowName+"爲第"+number+"個"+type+"客戶完成服務,耗時"+costTime/1000);
}else{
System.out.println(windowName+"沒有取到任務");
commonService();
}
}
}
主類:MainClass類,用for循環創建出4個普通的窗口,再創建出一個快速窗口和一個VIP窗口;接着創建三個定時器,分別定時去創建新的普通客戶號碼、快速客戶號碼、VIP客戶號碼,模擬不同的用戶來取號的過程。
代碼如下:
package itheima.interview.bankProject;
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.setWindowId(5);
expressWindow.start();
ServiceWindow vipWindow = new ServiceWindow();
vipWindow.setType(CustomerType.VIP);
vipWindow.setWindowId(6);
vipWindow.start();
<span style="font-family: Arial, Helvetica, sans-serif;"> </span>
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
new Runnable(){
@Override
public void run() {
Integer number =
NumberMachine.getInstance().getCommomManager().generateNewManager();
System.out.println(number+"號普通客戶等待服務!");
}
},
0,
Constants.COMMON_CUSTOMER_INTERVAL_TIME,
TimeUnit.SECONDS
);
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
new Runnable(){
@Override
public void run() {
Integer number =
NumberMachine.getInstance().getExpressManager().generateNewManager();
System.out.println(number+"號快速客戶等待服務!");
}
},
0,
5*Constants.COMMON_CUSTOMER_INTERVAL_TIME,
TimeUnit.SECONDS
);
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
new Runnable(){
@Override
public void run() {
Integer number =
NumberMachine.getInstance().getVipManager().generateNewManager();
System.out.println(number+"號VIP客戶等待服務!");
}
},
0,
10*Constants.COMMON_CUSTOMER_INTERVAL_TIME,
TimeUnit.SECONDS
);
}
}
常量:Constants類,把常用的常量定義到一個類中,用起來更加方便,程序的閱讀性更加高,所以建議以後都把常用的常量定義到一個類中。
代碼如下:
package itheima.interview.bankProject;
public class Constants {
public static int MAX_SERVICE_TIME = 10000;
public static int MIN_SERVICE_TIME = 1000;
public static int COMMON_CUSTOMER_INTERVAL_TIME = 1;
}