項目需求:
物件導向設計與分析:
有三種對應類型的客戶:VIP客戶,普通客戶,快速客戶 ,非同步隨機產生各種類型的客戶,各類型客戶在其對應視窗按順序依次辦理業務 。
首先,經常在銀行辦理業務的人更有利於理解本系統,例如,我經常陪老婆跑銀行,對銀行的這個業務算是比較熟悉了,我知道每一個客戶其實就是由銀行的一個取號機器產生號碼的方式來表示的。所以,我想到要有一個號碼管理器對象,讓這個對象不斷地產生號碼,就等於隨機產生了客戶。
由於有三類客戶,每類客戶的號碼編排都是完全獨立的,所以,我想到本系統一共要產生三個號碼管理器對象,各自管理一類使用者的排隊號碼。這三個號碼管理器對象統一由一個號碼機器進行管理,這個號碼機器在整個系統中始終只能有一個,所以,它要被設計成單例。
各類型客戶在其對應視窗按順序依次辦理業務 ,準確地說,應該是視窗依次叫號。
各個視窗怎麼知道該叫哪一個號了呢。它一定是問的相應的號碼管理器,即服務視窗每次找號碼管理器擷取當前要被服務的號碼。
import java.util.ArrayList;import java.util.List;/** * 針對不同使用者,有專門的號碼管理器 * 儲存客戶排隊號碼,和所有等待服務的客戶號碼集合 * @author ETHAN * */public class NumberManager {//上一次返回的號碼private int lastNumber = 1;private List<Integer> queueNumber = new ArrayList<Integer>();//同步public synchronized Integer generateNewNumber() {queueNumber.add(lastNumber);return lastNumber++;}//防止null,null 指標異常,拆箱 ----》intpublic synchronized Integer fetchServiceNumber() {if(queueNumber.size()>0) {return queueNumber.remove(0);//返回第一個} else {return null;}}}
/** * 一台機器,單例模式 * 針對不同使用者,有專門的號碼管理器 * @author ETHAN * */public class NumberMachine {//三種號碼管理器private NumberManager commonManager = new NumberManager();private NumberManager expressManager = new NumberManager();private NumberManager VIPManager = new NumberManager();private static NumberMachine numberMachine = new NumberMachine();private NumberMachine() {}public static NumberMachine getInstance() {return numberMachine;}public NumberManager getCommonManager() {return commonManager;}public void setCommonManager(NumberManager commonManager) {this.commonManager = commonManager;}public NumberManager getExpressManager() {return expressManager;}public void setExpressManager(NumberManager expressManager) {this.expressManager = expressManager;}public NumberManager getVIPManager() {return VIPManager;}public void setVIPManager(NumberManager vIPManager) {VIPManager = vIPManager;}}
public enum CustomerType {COMMON,EXPRESS,VIP;public String toString() {switch(this) {case COMMON:return "普通";case EXPRESS:return "快速";case VIP:return name();}return null;}}
public class Constants {//10秒,服務時間public static final int MAX_SERVICE_TIME = 10000;//1秒public static final int MIN_SERVICE_TIME = 1000;//普通使用者間隔1秒public static final int COMMON_CUSTOMER_INTERVAL_TIME = 1; }
服務視窗商務邏輯:
import java.util.Random;import java.util.concurrent.Executors;public class ServiceWindow {//視窗類別型private CustomerType type = CustomerType.COMMON;//普通視窗最多//視窗號碼private int windowId = 1;//視窗叫號,一個線程開始啟動public void start() {Executors.newSingleThreadExecutor().execute(new Runnable(){@Overridepublic void run() { switch(type) {case COMMON:while(true) {commonService();}case EXPRESS:while(true) {expressService();}case VIP:while(true) {VIPService();}}}});}private void commonService() {String windowName = "第"+windowId+"號"+type+"視窗";Integer number = NumberMachine.getInstance().getCommonManager().fetchServiceNumber();System.out.println(windowName+"正在擷取任務");if(number!=null) {//下邊為普通使用者服務,commonService(), type 還是為express,vipSystem.out.println(windowName+"正在為第"+number+"個"+"普通"+"客戶服務");long beginTime = System.currentTimeMillis();//9000int maxRand = Constants.MAX_SERVICE_TIME-Constants.MIN_SERVICE_TIME;//[0,9000)===[0,8999]---------->[1,9000]加1 後 ----- [1,10000]//公式:[min,max] === new Random().nextInt(max-min+1)+min;long serverTime = new Random().nextInt(maxRand)+1+Constants.MIN_SERVICE_TIME;try {Thread.sleep(serverTime);} catch (InterruptedException e) {e.printStackTrace();}long costTime = System.currentTimeMillis()-beginTime;System.out.println(windowName+"為第"+number+"個"+type+"客戶完成服務,耗時"+costTime/1000+"秒");} else {System.out.println(windowName+"沒有取到服務任務,沒有使用者。那就休息一秒鐘吧");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) {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) {long beginTime = System.currentTimeMillis();//9000int maxRand = Constants.MAX_SERVICE_TIME-Constants.MIN_SERVICE_TIME;//[0,9000)===[0,8999]---------->[1,9000]加1 後 ----- [1,10000]//公式:[min,max] === new Random().nextInt(max-min+1)+min;long serverTime = new Random().nextInt(maxRand)+1+Constants.MIN_SERVICE_TIME;try {Thread.sleep(serverTime);} catch (InterruptedException e) {e.printStackTrace();}long costTime = System.currentTimeMillis()-beginTime;System.out.println(windowName+"為第"+number+"個"+type+"客戶完成服務,耗時"+costTime/1000+"秒");} else {System.out.println(windowName+"沒有取到服務任務,沒有使用者。去為普通使用者服務");commonService();}}public CustomerType getType() {return type;}public void setType(CustomerType type) {this.type = type;}public int getWindowId() {return windowId;}public void setWindowId(int windowId) {this.windowId = windowId;}}
測試類別:
import java.util.concurrent.Executors;import java.util.concurrent.TimeUnit;public class MainClass {/** * @param args */public static void main(String[] args) {//預設為COMMON//產生四個普通視窗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();//一個VIP視窗ServiceWindow VIPWindow = new ServiceWindow();VIPWindow.setType(CustomerType.VIP);VIPWindow.start();//三個定時器,定時產生三種使用者//類比使用者到來,調度線程池,定時//使用者比例:1:6:3, 間隔時間 1:2:6Executors.newScheduledThreadPool(1).scheduleAtFixedRate(new Runnable() {@Overridepublic void run() {Integer number = NumberMachine.getInstance().getCommonManager().generateNewNumber();System.out.println(number+"號普通使用者等待服務。");}},0, Constants.COMMON_CUSTOMER_INTERVAL_TIME, TimeUnit.SECONDS);Executors.newScheduledThreadPool(1).scheduleAtFixedRate(new Runnable() {@Overridepublic void run() {Integer number = NumberMachine.getInstance().getExpressManager().generateNewNumber();System.out.println(number+"號普通使用者等待服務。");}},0, Constants.COMMON_CUSTOMER_INTERVAL_TIME*2, TimeUnit.SECONDS);Executors.newScheduledThreadPool(1).scheduleAtFixedRate(new Runnable() {@Overridepublic void run() {Integer number = NumberMachine.getInstance().getVIPManager().generateNewNumber();System.out.println(number+"號普通使用者等待服務。");}},0, Constants.COMMON_CUSTOMER_INTERVAL_TIME*6, TimeUnit.SECONDS);}}