黑馬程序員——銀行業務系統

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

 銀行業務調度系統

 

模擬實現銀行業務調度系統邏輯,具體需求如下:

1、銀行內有6個業務窗口,1- 4號窗口爲普通窗口,5號窗口爲快速窗口,6號窗口爲VIP窗口。

2、有三種對應類型的客戶:VIP客戶,普通客戶,快速客戶(辦理如交水電費、電話費之類業務的客戶)。

3、異步隨機生成各種類型的客戶,生成各類型用戶的概率比例爲:

4、VIP客戶 :普通客戶 :快速客戶 =  1 :6 :3。

5、客戶辦理業務所需時間有最大值和最小值,在該範圍內隨機設定每個VIP客戶以及普通客戶辦理業務所需的時間,快速客戶辦理業務所需時間爲最小值(提示:辦理業務的過程可通過線程Sleep的方式模擬)。

6、各類型客戶在其對應窗口按順序依次辦理業務。

7、當VIP(6號)窗口和快速業務(5號)窗口沒有客戶等待辦理業務的時候,這兩個窗口可以處理普通客戶的業務,而一旦有對應的客戶等待辦理業務的時候,則優先處理對應客戶的業務。

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

9、不要求實現GUI,只考慮系統邏輯實現,可通過Log方式展現程序運行結果。

根據去本地的農業銀行去觀察後,發現:

①、當我進入辦理大廳的時候,不是直接去找櫃檯的人員,而是從一臺機器上面選擇,我來幹什麼事。

②、從機器上面就會出現一張小票,上面有一個號碼

③、當櫃檯每辦理完一個人的業務以後,就會叫一個號碼,這個時候對應的號碼則過去辦理業務。

其實:當我去機器上面點擊產生號碼以後,他們的內部就會有一個排隊的信息。(當櫃檯的某一個工作位置空閒時,則按照排隊的順序進行取出)

下面借住張老師的一張程序圖(自己小小修改了一下):



代碼演示:設計一個號碼管理,這個號碼管理器管理則 客戶來生成 一個 獨立的id編號,而且還提供了給銀行櫃檯人員按照順序獲取編號,每獲取一個則少一個。

①、NumberManager類:

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

public class NumberManager		//號碼管理器。號碼管理器是 	內嵌在 號碼生成器中
{
	private Integer numberId = 1;
	
	List<Integer> idList = new ArrayList<Integer>();
	
	public synchronized Integer numberGenerator()		//號碼生成器,給人們使用,產生一個號碼(隊列結構)
	{
		idList.add(numberId);
		return numberId++;
	}
	
	
	public synchronized Integer numberFetch()		//給窗口的工作人員使用的
	{
		if(idList.size()>0)
		{
			return idList.remove(0);
		}
		else
			return null;
	}
}


②、代碼演示:當有一個號碼管理器以後,由於有3個不同的服務櫃檯,所服務的類別也有所差別。但是設計的時候他們最好都是從1臺機器上面出來的。因爲不可能爲某一個服務櫃檯去專門設計(一臺號碼生成器和號碼管理機器)。  我們設計出來的機器包含了3種服務類別,並且只能有一臺機器。(只能有一臺的話,就保證了唯一性,所以使用單例設計模式)

NumberMachine類:

public class NumberMachine		//3個不同的號碼管理器生成一臺機器,該機器不能在創建對象。必須單例
{
	private NumberManager commonManager = new NumberManager();	//創建普通櫃檯的 號碼管理器
	private NumberManager fastManager = new NumberManager();	//創建快速櫃檯的 號碼管理器
	private NumberManager vipManager = new NumberManager();	//創建VIP櫃檯的	 號碼管理器
	
	
	public NumberManager getCommonManager()	//返回普通櫃檯 的管理器對象,用作生成號碼,和取號
	{
		return commonManager;
	}
	public NumberManager getFastManager()//返回快速櫃檯 的管理器對象,用作生成號碼,和取號
	{
		return fastManager;
	}
	public NumberManager getVipManager()//返回vip櫃檯 的管理器對象,用作生成號碼,和取號
	{
		return vipManager;
	}
	
	
	
	/**創建單例的方法(餓漢式):
	 * 1、私有化構造方法
	 * 2、在內部自己創建一個自己的對象,並且私有化
	 * 3、通過一個靜態方法,返回自己的對象。
	 * */
	private  NumberMachine(){}
	private static NumberMachine instance = new NumberMachine();
	public static NumberMachine getInstance()
	{
		return instance;
	}
}


代碼演示:有了機器 現在設計 窗口,窗口的類型 只能有“普通,快速,vip”,所以呢。我們複習一下 enum 枚舉。

設計一個窗口,在構造方法中傳入 他的 類型(枚舉類型),和 窗口 編號(int)

設計一個方法,該方法可以開啓一個獨立的線程,該方法不斷的 去 取自己對應的號碼,如果取到則 進行下一步處理,如果沒有取到  則在屏幕打印休息一會兒 sleep。

如果  他 的類型是  vip 和  快速的話,他們還要查看一下 普通櫃檯是否需要幫忙。如果有就進行處理,如果還是沒有,就在屏幕打印休息一會兒 sleep。

③Type 枚舉類:

public enum Type
{
	COMMON,FAST,VIP;
	
	public String toString()
	{
		switch(this)			//調用我名字的時候,我就返回字符串
		{
			case COMMON:
				return "普通";
			case FAST:
				return "快速"; 
			case VIP:
				return "VIP";
		}
		return null;			
	}
}

開發過程中,將所有常使用的數字都封裝到一起(都是靜態的,都是不可變的)提高閱讀性:

④、StaticFinalFiedl():

public class StaticFinalField
{
	public static final int SLEEP_MAX = 10000;	//辦理業務最大時間
	public static final int SLEEP_MIN = 1000;		//辦理業務最小時間
}


⑤、ServiceWindow 服務窗口類:下面代碼有點亂,還請老師多多包含

import java.util.Random;
import java.util.concurrent.Executors;

public class ServiceWindow		//在構造方法中,需要傳入 窗口類別,和窗口號
{
	private Type type = null;	
	private int windowId ;
	
	public ServiceWindow(Type type,int windowId)
	{
		this.type = type;
		
		this.windowId = windowId;
	}
	
	
	public void start()		//調用我就開啓一個線程
	{
		Executors.newSingleThreadExecutor().execute(new Runnable(){
			public void run()
			{
				while(true)
				{
					switch(type)
					{
						case COMMON:
						commonService();
							break;
							
						case FAST:
						fastService();
							break;
							
						case VIP:
						vipService();
							break;
					}
				}
			}

			private void commonService()		//如果屬於 COMMON 類別。則使用這裏面的方法
			{
				System.out.println("第" + windowId + "號" + type +"窗口:取普通客戶--------");
				Integer commonNumber = NumberMachine.getInstance().getCommonManager().numberFetch();
				if(commonNumber !=null)
				{
					System.out.println("第" + windowId + "號" +  type  + "窗口:正在爲“" + commonNumber + "號”普通客人服務");
					
					/**生成普通客戶 辦理業務的 隨機時間
					 * */
					int sleepTime = new Random().nextInt(StaticFinalField.SLEEP_MAX - StaticFinalField.SLEEP_MIN) + StaticFinalField.SLEEP_MIN;
					try 
					{
						Thread.sleep(sleepTime);
					} 
					catch (InterruptedException e) 
					{
						e.printStackTrace();
					}
					
					System.out.println("第" + windowId + "號" + type + "窗口:爲" + commonNumber + "號普通客戶服務\"" + sleepTime/1000 + "\"秒" );
					
					
				}
				else
				{
					System.out.println("第" + windowId + "號" + type + "窗口:沒有獲取到普通客戶,休息一秒" );
					try 
					{
						Thread.sleep(StaticFinalField.SLEEP_MIN);
					} 
					catch (InterruptedException e) 
					{
						e.printStackTrace();
					}
				}
			}
			
			
			private void fastService()
			{
				System.out.println("第" + windowId + "號" + type +"窗口:取"+ type +"客戶--------");
				Integer fastNumber = NumberMachine.getInstance().getFastManager().numberFetch();
				if(fastNumber !=null)
				{
					System.out.println("第" + windowId + "號" +  type  + "窗口:正在爲“" + fastNumber + "號" + type +"”客人服務");
					
					/**快速客戶繳費就走。所以使用服務的時間是最短的
					 * */
					try 
					{
						Thread.sleep(StaticFinalField.SLEEP_MIN);		
					} 
					catch (InterruptedException e) 
					{
						e.printStackTrace();
					}
					
					System.out.println("第" + windowId + "號" + type + "窗口:爲“" + type  + fastNumber + "”號客戶服務\"" + StaticFinalField.SLEEP_MIN/1000 + "\"秒" );
				}
				else
				{
					System.out.println("第" + windowId + "號" + type + "窗口:"  +  "沒有獲取到快速客戶");
					/**如果快速客戶沒有用戶的話,那麼快速客戶將去查看普通客戶是否需要幫忙的
					 * */
					commonService();
				}
			}
			
			
			
			
			private void vipService()
			{
				System.out.println("第" + windowId + "號" + type +"窗口:取" + type + "客戶--------");
				Integer vipNumber = NumberMachine.getInstance().getVipManager().numberFetch();
				if(vipNumber !=null)
				{
					System.out.println("第" + windowId + "號" +  type  + "窗口:正在爲“" + vipNumber + "號" + type + "”客人服務");
					
					/**生成vip客戶 辦理業務的 隨機時間
					 * */
					int sleepTime = new Random().nextInt(StaticFinalField.SLEEP_MAX - StaticFinalField.SLEEP_MIN) + StaticFinalField.SLEEP_MIN;
					try 
					{
						Thread.sleep(sleepTime);
					} 
					catch (InterruptedException e) 
					{
						e.printStackTrace();
					}
					
					System.out.println("第" + windowId + "號" + type + "窗口:爲" + vipNumber + "號" + type + "客戶服務\"" + sleepTime/1000 + "\"秒" );
					
					
				}
				else
				{
					
					System.out.println("第" + windowId + "號" + type + "窗口:" + "沒有獲取到vip客戶");
					
					/**沒有vip客戶。則去幫忙普通客戶做業務
					 * */
					commonService();
				}
			}
		});
	}
}


代碼演示:隨機異步產生 3種客戶類型,在構造方法中創建3線程,每隔一段固定時間 則 創建 指定客戶。(1.5 新特性中的 線程池技術)

⑥、PersonRandom():

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

public class PersonRandom 
{
	
	PersonRandom()
	{
		Executors.newScheduledThreadPool(1).scheduleAtFixedRate(		//第一次1秒,隨後每秒運行一次線程,模擬來的普通客戶
				new Runnable(){
					public void run()
					{
						System.out.println("來了一個普通客戶,等待服務");
						NumberMachine.getInstance().getCommonManager().numberGenerator();
						System.out.println("普通客戶距離排隊還有:" + NumberMachine.getInstance().getCommonManager().idList.size());
					}		
				}, 
				1,
				1,
				TimeUnit.SECONDS);
		
		
		
		Executors.newScheduledThreadPool(1).scheduleAtFixedRate(		//第一次1秒,隨後2秒運行一次線程,模擬來的快速客戶
				new Runnable(){
					public void run()
					{
						System.out.println("來了一個快速客戶,等待服務");
						NumberMachine.getInstance().getFastManager().numberGenerator();
						System.out.println("快速客戶距離排隊還有:" + NumberMachine.getInstance().getFastManager().idList.size());
					}		
				}, 
				1,
				2,
				TimeUnit.SECONDS);
		
		
		Executors.newScheduledThreadPool(1).scheduleAtFixedRate(		//第一次3秒,隨後6秒運行一次線程,模擬來的VIP客戶
				new Runnable(){
					public void run()
					{
						System.out.println("來了一個vip客戶,等待服務");
						NumberMachine.getInstance().getVipManager().numberGenerator();
						System.out.println("vip客戶距離排隊還有:" + NumberMachine.getInstance().getVipManager().idList.size());
					}		
				}, 
				3,
				6,
				TimeUnit.SECONDS);
	}
}


⑦、所有的類都設計完成以後:他們都 只是一個 普通的類,沒有辦法將他們運行起來。在創建一個 MainClass  用作運行他們。

public class MainClass {

	public static void main(String[] args) 
	{
		
		new PersonRandom();		//構造方法中,開了3線程。模擬 3種客戶來的頻率
		
		
		for(int i=1; i<5; i++)		//開啓了4個普通窗口線程
		{
			new ServiceWindow(Type.COMMON,i).start();
		}

		new ServiceWindow(Type.FAST,5).start();		//開啓快速窗口線程
		new ServiceWindow(Type.VIP,6).start();		//開啓vip窗口線程

	}

}


還是附上我的效果,我想應該是正確的

第1號普通窗口:取普通客戶--------
第3號普通窗口:取普通客戶--------
第2號普通窗口:取普通客戶--------
第5號快速窗口:取快速客戶--------
第4號普通窗口:取普通客戶--------
第6號VIP窗口:取VIP客戶--------
第1號普通窗口:沒有獲取到普通客戶,休息一秒
第3號普通窗口:沒有獲取到普通客戶,休息一秒
第2號普通窗口:沒有獲取到普通客戶,休息一秒
第5號快速窗口:沒有獲取到快速客戶
第5號快速窗口:取普通客戶--------
第5號快速窗口:沒有獲取到普通客戶,休息一秒
第4號普通窗口:沒有獲取到普通客戶,休息一秒
第6號VIP窗口:沒有獲取到vip客戶
第6號VIP窗口:取普通客戶--------
第6號VIP窗口:沒有獲取到普通客戶,休息一秒
來了一個普通客戶,等待服務
普通客戶距離排隊還有:1
來了一個快速客戶,等待服務
快速客戶距離排隊還有:1
第3號普通窗口:取普通客戶--------
第1號普通窗口:取普通客戶--------
第3號普通窗口:正在爲“1號”普通客人服務
第5號快速窗口:取快速客戶--------
第6號VIP窗口:取VIP客戶--------
第6號VIP窗口:沒有獲取到vip客戶
第6號VIP窗口:取普通客戶--------
第2號普通窗口:取普通客戶--------
第4號普通窗口:取普通客戶--------
第2號普通窗口:沒有獲取到普通客戶,休息一秒
第6號VIP窗口:沒有獲取到普通客戶,休息一秒
第5號快速窗口:正在爲“1號快速”客人服務
第1號普通窗口:沒有獲取到普通客戶,休息一秒
第4號普通窗口:沒有獲取到普通客戶,休息一秒
來了一個普通客戶,等待服務
普通客戶距離排隊還有:1
第6號VIP窗口:取VIP客戶--------
第5號快速窗口:爲“快速1”號客戶服務"1"秒
第5號快速窗口:取快速客戶--------
第5號快速窗口:沒有獲取到快速客戶
第5號快速窗口:取普通客戶--------
第5號快速窗口:正在爲“2號”普通客人服務
第2號普通窗口:取普通客戶--------
第6號VIP窗口:沒有獲取到vip客戶
第6號VIP窗口:取普通客戶--------
第6號VIP窗口:沒有獲取到普通客戶,休息一秒
第2號普通窗口:沒有獲取到普通客戶,休息一秒
第4號普通窗口:取普通客戶--------
第4號普通窗口:沒有獲取到普通客戶,休息一秒
第1號普通窗口:取普通客戶--------
第1號普通窗口:沒有獲取到普通客戶,休息一秒


尊敬的老師:ServiceWindow 的代碼稍微有點囉嗦,有點亂,還請老師多多包含一下。


銀行調度系統學習的知識:小結

NumberManager類:①、隊列數據結構(先進先出。我想如果使用LinkedList 可能效率要更高點兒 )。 ②、後++,先進行賦值,然後在自增。

NumberMachine類:①、單例設計模式。②我自己創建了其他類對象,通過我的方法給你返回其他類的對象,保證其他類的唯一性。

Type 枚舉類:①、你只能使用我這裏面的元素(限定元素)。②在 覆蓋toString的時候, switch 後面的括號跟上this,本來對象。

StaticFinalField類:①既然是固定的元素值的話,就  static ,然後也不能改變。(我想話,應該還是可以使用 枚舉來完成,不過枚舉的 參數列表必須是同一個類型)

ServiceWindow類:①創建一個普通類,通過 一個方法 裏面 嵌套 線程池 就可以開啓一個線程(當每一個對象不同的話,就可以開啓不同的線程,我現在感覺Thread就有那麼一點兒像)②複習了一下  switch 。 ③(其實應該像張老師說的那樣,使用模版設計模式,老師海涵,我想進入44期)。

PersonRandom類:①這是在紅綠燈學到的,創建一個類,然後在這個類中 嵌入 線程,只要 其他  地方 實例化 本類,那麼 我 嵌入的線程就開啓了。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章