標籤:
1.瞭解銀行業務調度系統的工作流程與原理
銀行裡有三種視窗,一種是普通視窗,一種是VIP視窗,一種是快速視窗,所有客戶都要領號排隊,當VIP視窗或快速視窗空閑時,可以為普通視窗服務。
2.銀行業務調度系統的項目需求
· 銀行內有6個業務視窗,1 - 4號視窗為普通視窗,5號視窗為快速視窗,6號視窗為VIP視窗。
· 有三種對應類型的客戶:VIP客戶,普通客戶,快速客戶(辦理如交水電費、電話費之類業務的客戶)。
· 非同步隨機產生各種類型的客戶,產生各類型使用者的機率比例為:
VIP客戶:普通客戶:快速客戶 = 1 :6 :3。
· 客戶辦理業務所需時間有最大值和最小值,在該範圍內隨機設定每個VIP客戶以及普通客戶辦理業務所需的時間,快速客戶辦理業務所需時間為最小值(提示:辦理業務的過程可通過線程Sleep的方式類比)。
· 各類型客戶在其對應視窗按順序依次辦理業務。
· 當VIP(6號)視窗和快速業務(5號)視窗沒有客戶等待辦理業務的時候,這兩個視窗可以處理普通客戶的業務,而一旦有對應的客戶等待辦理業務的時候,則優先處理對應客戶的業務。
· 隨機產生客戶時間間隔以及業務辦理時間最大值和最小值自定,可以設定。
· 不要求實現GUI,只考慮系統邏輯實現,可通過Log方式展現程式運行結果。
3.物件導向思想實現銀行業務調度系統
服務視窗類(ServiceWindow):封裝了“普通服務”,“快速服務”,“VIP服務”三個方法,通過枚舉CustomerType的值區分,並分別調用這三種方法。
三種服務的邏輯:首先擷取“服務號碼”(通過號碼產生器產生),設定一定的服務時間,服務時間一過則執行完畢。
實現如下:
package cn.itcast.bankqueue;import java.util.Random;import java.util.concurrent.Executors;import java.util.logging.Logger;/**服務視窗類: * 沒有把VIP視窗和快速視窗做成子類,是因為實際業務中的普通視窗可以隨時被設定為VIP視窗和快速視窗。 * */public class ServiceWindow {
//列印資訊private static Logger logger = Logger.getLogger("cn.itcast.bankqueue");
//CustomerType枚舉類,區分三種服務,這裡預設普通服務private CustomerType type = CustomerType.COMMON;private int number = 1;public CustomerType getType() {return type;} //設定不同的服務public void setType(CustomerType type) {this.type = type;}public void setNumber(int number){this.number = number;}//開始執行3種服務中的一種public void start(){Executors.newSingleThreadExecutor().execute(new Runnable(){public void run(){//下面這種寫法的運行效率低,最好是把while放在case下面while(true){switch(type){case COMMON:commonService();break;case EXPRESS:expressService();break;case VIP:vipService();break;}}}});}//普通服務private void commonService(){String windowName = "第" + number + "號" + type + "視窗";System.out.println(windowName + "開始擷取普通任務!");Integer serviceNumber = NumberMachine.getInstance().getCommonManager().fetchNumber();if(serviceNumber != null ){System.out.println(windowName + "開始為第" + serviceNumber + "號普通客戶服務");int maxRandom = Constants.MAX_SERVICE_TIME - Constants.MIN_SERVICE_TIME;int serviceTime = new Random().nextInt(maxRandom)+1 + Constants.MIN_SERVICE_TIME;try {Thread.sleep(serviceTime);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(windowName + "完成為第" + serviceNumber + "號普通客戶服務,總共耗時" + serviceTime/1000 + "秒");}else{System.out.println(windowName + "沒有取到普通任務,正在空閑一秒");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}//快速服務private void expressService(){Integer serviceNumber = NumberMachine.getInstance().getExpressManager().fetchNumber();String windowName = "第" + number + "號" + type + "視窗";System.out.println(windowName + "開始擷取快速任務!");if(serviceNumber !=null){System.out.println(windowName + "開始為第" + serviceNumber + "號快速客戶服務");int serviceTime = Constants.MIN_SERVICE_TIME;try {Thread.sleep(serviceTime);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(windowName + "完成為第" + serviceNumber + "號快速客戶服務,總共耗時" + serviceTime/1000 + "秒");}else{System.out.println(windowName + "沒有取到快速任務!");commonService();}}//VIP服務private void vipService(){Integer serviceNumber = NumberMachine.getInstance().getVipManager().fetchNumber();String windowName = "第" + number + "號" + type + "視窗";System.out.println(windowName + "開始擷取VIP任務!");if(serviceNumber !=null){System.out.println(windowName + "開始為第" + serviceNumber + "號VIP客戶服務");int maxRandom = Constants.MAX_SERVICE_TIME - Constants.MIN_SERVICE_TIME;int serviceTime = new Random().nextInt(maxRandom)+1 + Constants.MIN_SERVICE_TIME;try {Thread.sleep(serviceTime);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(windowName + "完成為第" + serviceNumber + "號VIP客戶服務,總共耗時" + serviceTime/1000 + "秒");}else{System.out.println(windowName + "沒有取到VIP任務!");commonService();}}}
客戶類型枚舉類(CustomerType):通過枚舉類,區分三種類型的客戶
實現如下:
package cn.itcast.bankqueue;public enum CustomerType {COMMON,EXPRESS,VIP;public String toString(){String name = null;switch(this){case COMMON:name = "普通";break;case EXPRESS:name = "快速";break;case VIP:name = name();break;}return name;}}
號碼產生器類(NumberMachine):內建三種號碼產生管理器對應三種服務。
實現如下:
package cn.itcast.bankqueue;//號碼產生器:設計成單例模式,達到多線程操作一份資料的目的public class NumberMachine {private NumberMachine(){}private static NumberMachine instance = new NumberMachine();public static NumberMachine getInstance(){return instance;}//三種號碼產生管理器private NumberManager commonManager = new NumberManager();private NumberManager expressManager = new NumberManager();private NumberManager vipManager = new NumberManager();//擷取某個號碼產生管理器public NumberManager getCommonManager() {return commonManager;}public NumberManager getExpressManager() {return expressManager;}public NumberManager getVipManager() {return vipManager;}}
號碼產生管理器類(NumberManager):使用同步機制實現號碼的產生和儲存。
實現如下:
package cn.itcast.bankqueue;import java.util.ArrayList;import java.util.List;//號碼產生管理器:用ArrayList來儲存產生的號碼,並只從第一個號碼開始擷取,達到先來先得號碼的效果public class NumberManager {private int lastNumber = 0;private List queueNumbers = new ArrayList();public synchronized Integer generateNewNumber(){queueNumbers.add(++lastNumber);return lastNumber;}public synchronized Integer fetchNumber(){if(queueNumbers.size()>0){return (Integer)queueNumbers.remove(0);}else{return null;}}}
常量值類(Constants):儲存一些常量的資訊
實現如下:
package cn.itcast.bankqueue;public class Constants {public static int MAX_SERVICE_TIME = 10000; //10秒!public static int MIN_SERVICE_TIME = 1000; //1秒!/*每個普通視窗服務一個客戶的平均時間為5秒,一共有4個這樣的視窗,也就是說銀行的所有普通視窗合起來 * 平均1.25秒內可以服務完一個普通客戶,再加上快速視窗和VIP視窗也可以服務普通客戶,所以, * 1秒鐘產生一個普通客戶比較合理,*/public static int COMMON_CUSTOMER_INTERVAL_TIME = 1; }
啟動程式(main):
package cn.itcast.bankqueue;import java.util.concurrent.Executors;import java.util.concurrent.TimeUnit;import java.util.logging.Logger;public class MainClass {private static Logger logger = Logger.getLogger("cn.itcast.bankqueue");public static void main(String[] args) {//產生4個普通視窗for(int i=1;i<5;i++){ServiceWindow window = new ServiceWindow();window.setNumber(i);window.start();}//產生1個快速視窗ServiceWindow expressWindow = new ServiceWindow();expressWindow.setType(CustomerType.EXPRESS);expressWindow.start();//產生1個VIP視窗ServiceWindow vipWindow = new ServiceWindow();vipWindow.setType(CustomerType.VIP);vipWindow.start();//普通客戶拿號Executors.newScheduledThreadPool(1).scheduleAtFixedRate(new Runnable(){public void run(){Integer serviceNumber = NumberMachine.getInstance().getCommonManager().generateNewNumber();/** * 採用logger方式,無法看到直觀的運行效果,因為logger.log方法內部並不是直接把內容列印出出來, * 而是交給內部的一個線程去處理,所以,列印出來的結果在時間順序上看起來很混亂。 *///logger.info("第" + serviceNumber + "號普通客戶正在等待服務!");System.out.println("第" + serviceNumber + "號普通客戶正在等待服務!");}},0,Constants.COMMON_CUSTOMER_INTERVAL_TIME, TimeUnit.SECONDS);//快速客戶拿號Executors.newScheduledThreadPool(1).scheduleAtFixedRate(new Runnable(){public void run(){Integer serviceNumber = NumberMachine.getInstance().getExpressManager().generateNewNumber();System.out.println("第" + serviceNumber + "號快速客戶正在等待服務!");}},0,Constants.COMMON_CUSTOMER_INTERVAL_TIME * 2, TimeUnit.SECONDS);//VIP客戶拿號Executors.newScheduledThreadPool(1).scheduleAtFixedRate(new Runnable(){public void run(){Integer serviceNumber = NumberMachine.getInstance().getVipManager().generateNewNumber();System.out.println("第" + serviceNumber + "號VIP客戶正在等待服務!");}},0,Constants.COMMON_CUSTOMER_INTERVAL_TIME * 6, TimeUnit.SECONDS);}}
總結:
1.首先瞭解項目的需求
2.清楚每個需求模組的商務邏輯(重要)
3.以物件導向思想思考:涉及到什麼類,類與類之間關係。
4.開始實現功能,後期對代碼進行重構,最佳化。
java-銀行業務調度系統《十一》