---------------------- android培訓、java培訓、期待與您交流! ----------------------
銀行業務調度系統的項目需求:
面向對象的分析與設計:有三種對應類型的客戶:
VIP客戶,普通客戶,快速客戶 ,異步隨機生成各種類型的客戶,各類型客戶在其對應窗口按順序依次辦理業務 。
- 首先,經常在銀行辦理業務的人更有利於理解本系統,例如,我經常陪老婆跑銀行,對銀行的這個業務算是比較熟悉了,我知道每一個客戶其實就是由銀行的一個取號機器產生號碼的方式來表示的。所以,我想到要有一個號碼管理器對象,讓這個對象不斷地產生號碼,就等於隨機生成了客戶。
- 由於有三類客戶,每類客戶的號碼編排都是完全獨立的,所以,我想到本系統一共要產生三個號碼管理器對象,各自管理一類用戶的排隊號碼。這三個號碼管理器對象統一由一個號碼機器進行管理,這個號碼機器在整個系統中始終只能有一個,所以,它要被設計成單例。
- 各個窗口怎麼知道該叫哪一個號了呢?它一定是問的相應的號碼管理器,即服務窗口每次找號碼管理器獲取當前要被服務的號碼。
- 如果我不是多次親身經歷銀行的這種業務,再加之積累了大量面向對象的應用開發經驗,我也不知道能否輕鬆進行這種設計,能否發掘出其中隱含的對象信息,我真說不出具體的經驗是什麼,就是日積月累出來的一種感覺。難道這就是傳說中的:“只可意會,不可言傳?”
NumberManager和NumberMachine類:
NumberManager類
定義一個用於存儲上一個客戶號碼的成員變量和用於存儲所有等待服務的客戶號碼的隊列集合。
定義一個產生新號碼的方法和獲取馬上要爲之服務的號碼的方法,這兩個方法被不同的線程操作了相同的數據,所以,要進行同步。
NumberMachine類
定義三個成員變量分別指向三個NumberManager對象,分別表示普通、快速和VIP客戶的號碼管理器,定義三個對應的方法來返回這三個NumberManager對象。
將NumberMachine類設計成單例。package it.cast.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 generateNumber() { queueNumber.add(lastNumber); return lastNumber++; } public synchronized Integer fetchServiceNumber() { if(queueNumber.size() > 0) { return queueNumber.remove(0); } else { return null; } } }
ServiceWindow與CustomerType枚舉類:package it.cast.bank; public class NumberMachine { 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; } private NumberMachine(){} public static NumberMachine getInstance() { return instance; } private static NumberMachine instance = new NumberMachine(); }
CustomerType枚舉類
系統中有三種類型的客戶,所以用定義一個枚舉類,其中定義三個成員分別表示三種類型的客戶。
重寫toString方法,返回類型的中文名稱。這是在後面編碼時重構出來的,剛開始不用考慮。
ServiceWindow類
定義一個start方法,內部啓動一個線程,根據服務窗口的類別分別循環調用三個不同的方法。
定義三個方法分別對三種客戶進行服務,爲了觀察運行效果,應詳細打印出其中的細節信息。package it.cast.bank; public enum CustomerType { COMMON,EXPERSS,VIP; public String toString(){ String name = null; switch(this) { case COMMON: name = "普通"; break; case EXPERSS: name = "快速"; break; case VIP: name = name(); break; } return name; } }
package it.cast.bank; import java.util.Random; import java.util.concurrent.Executors; public class ServiceWindow { private CustomerType type = CustomerType.COMMON; private int number = 1; public void start() { Executors.newSingleThreadExecutor().execute(new Runnable() { public void run() { while(true) { switch(type) { case COMMON: commonService(); break; case EXPERSS: expressService(); break; case VIP: vipService(); break; } } } }); } protected void vipService() { // TODO Auto-generated method stub String windowName = "第"+number+"號"+type+"窗口"; System.out.println(windowName+"開始獲取普通任務"); Integer serviceNumber = NumberMachine.getInstance().getCommonManager().fetchServiceNumber(); 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) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(windowName + "完成爲第"+serviceNumber+"號普通客戶服務,總共耗時"+serviceTime/1000+"秒"); } else { System.out.println(windowName+"沒有取到普通任務,正在空閒一秒"); commonService(); } } protected void expressService() { String windowName = "第"+number+"號"+type+"窗口"; System.out.println(windowName+"開始獲取快速任務"); Integer serviceNumber = NumberMachine.getInstance().getExpressManager().fetchServiceNumber(); if(serviceNumber != null) { System.out.println(windowName+"開始爲第"+serviceNumber+"號普通客戶服務"); int maxRandom = Constants.MAX_SERVICE_TIME - Constants.MIN_SERVICE_TIME; int serviceTime = Constants.MIN_SERVICE_TIME; try { Thread.sleep(serviceTime); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(windowName + "完成爲第"+serviceNumber+"號普通客戶服務,總共耗時"+serviceTime/1000+"秒"); } else { System.out.println(windowName+"沒有取到快速任務,正在空閒一秒"); try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } protected void commonService() { String windowName = "第"+number+"號"+type+"窗口"; System.out.println(windowName+"開始獲取VIP任務"); Integer serviceNumber = NumberMachine.getInstance().getVipManager().fetchServiceNumber(); 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) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(windowName + "完成爲第"+serviceNumber+"號普通客戶服務,總共耗時"+serviceTime/1000+"秒"); } else { System.out.println(windowName+"沒有取VIP任務"); try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public CustomerType getType() { return type; } public void setType(CustomerType type) { this.type = type; } public void setNumber(int number) { this.number = number; } }
MainClass類與Constants類:
MainClass類
用for循環創建出4個普通窗口,再創建出1個快速窗口和一個VIP窗口。
接着再創建三個定時器,分別定時去創建新的普通客戶號碼、新的快速客戶號碼、新的VIP客戶號碼。
Constants類
定義三個常量:MAX_SERVICE_TIME、MIN_SERVICE_TIME、COMMON_CUSTOMER_INTERVAL_TIMEpackage it.cast.bank; 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; }
package it.cast.bank; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import javax.management.ServiceNotFoundException; public class MainClass { /** * @param args */ 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.EXPERSS); expressWindow.start(); //產生1個VIP窗口 ServiceWindow vipWindow = new ServiceWindow(); vipWindow.setType(CustomerType.VIP); vipWindow.start(); //普通客戶拿號 Executors.newScheduledThreadPool(1).scheduleAtFixedRate( new Runnable() { public void run() { // TODO Auto-generated method stub Integer serviceNumber = NumberMachine.getInstance().getCommonManager().generateNumber(); System.out.println("第"+serviceNumber+"號普通客戶正在等待服務"); } }, 0, Constants.COMMON_CUSTOMER_INTERVAL_TIME, TimeUnit.SECONDS); //快速客戶拿號 Executors.newScheduledThreadPool(1).scheduleAtFixedRate( new Runnable() { public void run() { // TODO Auto-generated method stub Integer serviceNumber = NumberMachine.getInstance().getExpressManager().generateNumber(); System.out.println("第"+serviceNumber+"號快速客戶正在等待服務"); } }, 0, Constants.COMMON_CUSTOMER_INTERVAL_TIME * 2, TimeUnit.SECONDS); //VIP客戶拿號 Executors.newScheduledThreadPool(1).scheduleAtFixedRate( new Runnable() { public void run() { // TODO Auto-generated method stub Integer serviceNumber = NumberMachine.getInstance().getVipManager().generateNumber(); System.out.println("第"+serviceNumber+"號VIP客戶正在等待服務"); } }, 0, Constants.COMMON_CUSTOMER_INTERVAL_TIME * 6, TimeUnit.SECONDS); } }