《黑馬程序員》--銀行業務調度系統

------- android培訓java培訓、期待與您交流! ----------

銀行業務調度系統:

需求分析:

1.銀行內有6個業務窗口,1到4號個是普通窗口,5號快速窗口,6號VIP窗口。

2.有三種對應類型的客戶,普通客戶,快速客戶,VIP客戶。

3.異步隨機生成三種客戶。比例普通:快速:VIP 爲 6:3:1

4.辦理時間有最大和最小值,在該範圍內隨機設定VIP客戶和普通客戶的時間。

快速客戶辦理時間相等且爲最小值。辦理業務可以通過Sleep方式。

5.那種類型客戶在哪種辦理。當快速窗口和VIP窗口有空閒時,可以處理普通客戶業務,

當有快速和VIP客戶時,就優先處理普通客戶。

6.隨機生成客戶時間間隔以及辦理業務時間最大值和最小值自定,可以設置。

7.不要求實現GUI圖像界面,只考慮邏輯實現,可通過Log方式展示程序運行結果 。

----------------------------------------------------------------------------------------------------------------

面向對象的分析設計

一。有三種類型客戶對應三種類型的窗口。VIP 、普通、快速:異步隨機生成各個類型的客戶,各種類型客戶對應窗口按順序依次辦理業務

1、    首先,在現實中,進來一個客戶就先在取號機上取到一個號碼,因此,要設計一種號碼管理器對象,讓這個對象不斷地產生號碼,就相當於隨機生成了客戶
2、    由於有三種類型的客戶,每種類型的客戶的號碼編排都完全獨立,所以,本系統一共要產生三個號碼管理器對象,各自管理一類用戶的排隊號碼。這三個號碼管理器對象統一由一個號碼機器進行管理,這個取碼機在整個系統中始終只能有一個,所以,設計成單例合適
 
二、各類型客戶在其對應窗口按順序依次辦理業務,既窗口依次叫號,各個窗口怎麼知道該叫哪一個號了呢?它是問的相應的號碼管理器,即服務窗口每次找號碼管理器獲取當前要被服務的號碼
 
項目中設計了6個類,分別是NumberManager類、NumberMachine類、CustomerType枚舉類、ServiceWindow類、Constants類、MainClass類,

下面就具體看下這些類

-------------------------------------------------------------------------------------------------------------------

NumberManager類
1、定義一個用於存儲上客戶號碼的成員變量和存儲所有等待服務的客戶號碼的隊列集合

2、定義一個產生新號碼的方法和獲取馬上要爲之服務的號碼的方法,這兩個方法被不同的線程操作了相同的數據,所以,要進行同步

package com.itcast.bank;

import java.util.ArrayList;
import java.util.List;

public class NumberManager {

/**
* 定義一個用於存儲上客戶號碼的成員變量
*/
private int lastNumber = 1;
/**
* 存儲所有等待服務的客戶號碼的隊列集合
*/
private List<Integer> queueNumber = new ArrayList<Integer>();

/**
* generate 形成,引起,產生,造成
* 
* 生成號碼機器生成新的號碼,並存儲在隊列號裏面
* @return 新生成的號碼
*/
public synchronized Integer generateNewManager(){
queueNumber.add(lastNumber);
return lastNumber++;
} 

/**
* fetch 接來,拿取,抵達,售得
* 
* 拿取服務號碼
* @return 新生成的號碼
* 在這裏萬一取到null沒有取到0就會報異常 null 轉成整數 就會成空指針異常。 
* Integer 自動拆箱裝箱。
*/
public synchronized Integer fetchServiceNumber(){
Integer number = null;
if(queueNumber.size() > 0){
number = queueNumber.remove(0);
}
return number;
}

}


--------------------------------------------------------------------------------------------------------------------------------------------------------

NumberMachine類
1、定義三個成員變量分別指向三個NumberManager對象,分別表示普通、快速和VIP客戶的號碼管理器,定義三個對應的方法來返回這三個NumberManager對象。
2、將NumberMachine類設計成單例。


package com.itcast.bank;


/**
 * 返回三個關係
 * @author Administrator
 *
 */
public class NumberMachine {

/**
* 定義三個成員變量分別指向三個NumberManager對象,
* 分別表示普通、快速和VIP客戶的號碼管理器
*/

private NumberManager commonManager = new NumberManager();
private NumberManager expressManager = new NumberManager();
private NumberManager vipManager = new NumberManager();
/**
* 定義三個對應的方法來返回這三個NumberManager對象。
* @return NumberManager對象
*/

public NumberManager getCommonManager() {
return commonManager;
}
public NumberManager getExpressManager() {
return expressManager;
}
public NumberManager getVipManager() {
return vipManager;
}

/**
* 單例模式有一個靜態方法
* 不能創建對象+
*/
private NumberMachine(){}
public static NumberMachine getInstance(){
return instance ;
}

private static NumberMachine  instance = new NumberMachine();

}

---------------------------------------------------------------------------------------------------------------------------------------------------------

CustomerType枚舉類
1、系統中有三種類型的客戶,所以用定義一個枚舉類,其中定義三個成員分別表示三種類型的客戶。
2、重寫toString方法,返回類型的中文名稱。這是在後面編碼時重構出來的,剛開始不用考慮。

package com.itcast.bank;

/**
 * 系統中有三種類型的客戶,所以用定義一個枚舉類,
 * 其中定義三個成員分別表示三種類型的客戶
 *
 */
public enum CustomerType {
COMMON,EXPRESS,VIP;

/**
* 便於方便觀看 用中文覆蓋代替
*/

public String toString(){
switch(this){
case COMMON:
return "普通";
case EXPRESS:
return "快速";
case VIP:
return name();
}
return null;
}
}

----------------------------------------------------------------------------------------------------------------------------------------------------------

ServiceWindow類
1、定義一個start方法,內部啓動一個線程,根據服務窗口的類別分別循環調用三個不同的方法。
2、定義三個方法分別對三種客戶進行服務,爲了觀察運行效果,應詳細打印出其中的細節信息


 package com.itcast.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;
}

/**
* 定義一個start方法,內部啓動一個線程,
* 根據服務窗口的類別分別循環調用三個不同的方法。
* executors 執行者;實行者;遺囑執行人
*/
public void start()
{
Executors.newSingleThreadExecutor().execute(new Runnable()
{
public void run()
{
while(true)
{
switch(type)
{
/**
* 根據type類型 來生成不同的
*/
case COMMON:
commonService();
break;
case EXPRESS:
expressService();
break;
case VIP:
vipService();
break;
}
}
}
}); 
}

/**
* 定義三個方法分別對三種客戶進行服務,
* 爲了觀察運行效果,應詳細打印出其中的細節信息
*/


private void commonService() {
String windowName = "第"+windowId + "號" + type +"窗口";
/**
* 用Integer而不用int  因爲fetchServiceNumber() 可能拿到空值。就會報異常
*/
Integer number = NumberMachine.getInstance().getCommonManager().fetchServiceNumber();
System.out.println(windowName + "正在獲取任務");
if(number != null){
System.out.println(windowName + "正在爲第" + number + "個" + "普通" + "客戶服務" );
long beginTime = System.currentTimeMillis();
/**
* 最大的隨機值maxRandom
*/
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{
System.out.println(windowName + "沒有取到任務,先休息一秒鐘吧!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

private void expressService() {
String windowName = "第"+windowId + "號" + type +"窗口";
/**
* 用Integer而不用int  因爲fetchServiceNumber() 可能拿到空值。就會報異常
*/
Integer number = NumberMachine.getInstance().getExpressManager().fetchServiceNumber();
System.out.println(windowName + "正在獲取任務");
if(number != null){
System.out.println(windowName + "正在爲第" + number + "個" + type + "客戶服務" );
long beginTime = System.currentTimeMillis();
/**
* 最大的隨機值maxRandom
*/
//int maxRand = Constants.MAX_SERVICE_TIME - Constants.MIN_SERVICE_TIME;
//long serveTime = new Random().nextInt(maxRand) + 1 + Constants.MIN_SERVICE_TIME;
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而不用int  因爲fetchServiceNumber() 可能拿到空值。就會報異常
*/
Integer number = NumberMachine.getInstance().getCommonManager().fetchServiceNumber();
System.out.println(windowName + "正在獲取任務");
if(number != null){
System.out.println(windowName + "正在爲第" + number + "個" + type + "客戶服務" );
long beginTime = System.currentTimeMillis();
/**
* 最大的隨機值maxRandom
*/
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();

}
}


}

-------------------------------------------------------------------------------------------------------------------------------------------------

Constants類
這個用用於存在系統中使用的常量,這樣做可以便於系統的維護,它內部定義三個常量:MAX_SERVICE_TIME、MIN_SERVICE_TIME、COMMON_CUSTOMER_INTERVAL_TIME

package com.itcast.bank;


/**
 * 常量專門定義一個類
 */
public class Constants {
public static int MAX_SERVICE_TIME = 10000;
public static int MIN_SERVICE_TIME = 1000;

/**
* 每個普通窗口服務一個客戶的平均時間爲5秒,一共有4個這樣的窗口,也就是說銀行的所有普通窗口合起來
* 平均1.25秒內可以服務完一個普通客戶,再加上快速窗口和VIP窗口也可以服務普通客戶,所以,1秒鐘
* 產生一個普通客戶比較合理,
*/   

public static int COMMON_CUSTOMER_INTERVAL_TIME = 1;
}

----------------------------------------------------------------------------------------------------------------------------------------------------------


MainClass類
1、這個類是main方法所在類用
2、for循環創建出4個普通窗口,再創建出1個快速窗口和一個VIP窗口
3、接着再創建三個定時器,分別定時去創建新的普通客戶號碼、新的快速客戶號碼、新的VIP客戶號碼

package com.itcast.bank;


import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;


public class MainClass {


/**
* common : express : vip = 6 : 3 : 1
* @param args
*/
public static void main(String[] args) 
{

/**
* for循環創建出4個普通窗口
*/
for(int i=1; i<5; i++)
{
/**
* see name know it meaning 起名字時要見名知意
*/
ServiceWindow commonWindow = new ServiceWindow();
commonWindow.setWindowId(i);
commonWindow.start();

}

/**
* 創建出1個快速窗口
*/
ServiceWindow expressWindow = new ServiceWindow();
expressWindow.setType(CustomerType.EXPRESS);
expressWindow.start();

/**
* 一個VIP窗口
*/
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 + "號普通客戶正在等待服務" );
}
},//command
0,//initialDelay
Constants.COMMON_CUSTOMER_INTERVAL_TIME,//period
TimeUnit.SECONDS     //unit
);
/**
* 創建快速客戶定時器
*/
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
new Runnable(){
public void run(){
Integer number = NumberMachine.getInstance().getExpressManager().generateNewManager();
System.out.println(number + "號快速客戶正在等待服務" );
}
},
0,
Constants.COMMON_CUSTOMER_INTERVAL_TIME * 2,
TimeUnit.SECONDS    
);
/**
* 創建VIP客戶定時器
*/
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
new Runnable(){
public void run(){
Integer number = NumberMachine.getInstance().getVipManager().generateNewManager();
System.out.println(number + "號VIP客戶正在等待服務" );
}
},
0,
Constants.COMMON_CUSTOMER_INTERVAL_TIME * 6,
TimeUnit.SECONDS     
);
}


}


------- android培訓java培訓、期待與您交流! ----------
發佈了45 篇原創文章 · 獲贊 7 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章