1. 程式人生 > >【黑馬程式設計師】7K面試題之銀行排程系統

【黑馬程式設計師】7K面試題之銀行排程系統

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

Ø        銀行內有6個業務視窗,1- 4號視窗為普通視窗,5號視窗為快速視窗,6號視窗為VIP視窗。

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

Ø        非同步隨機生成各種型別的客戶,生成各型別使用者的概率比例為:

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

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

Ø        各型別客戶在其對應視窗按順序依次辦理業務。

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

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

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

需求分析:

基本邏輯:

客戶:來到銀行後,先取號。取號後等待視窗喊號。然後到相應視窗辦理好業務後離開銀行。

視窗:根據順序喊號,為客戶辦理好業務後,按照順序繼續喊號。視窗為三種類型,對應視窗為對對應客戶服務。

號碼產生管理器:客戶來到銀行後按順序給客戶產生排隊號。然後把號碼分配給各個視窗。這個號碼管理產生器為單例(即只有一個)。即使有多個取號機器,但是多個取號機器操作的是“唯一”的一個號碼管理器。

專案所需類:

視窗類:ServiceWindow

視窗有ID、型別等一系列屬性;

視窗建立後,開始自動工作。不斷檢視客戶列表是否有客戶,有的話為列表第一個客戶辦理業務,然後稍微休息一下繼續為下一位客戶辦理業務;如果沒有客戶,也稍微休息一下然後繼續看有沒有客戶到來。

package com.itcast;

import com.itcast.NumberManager;

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

public class ServiceWindow {
	int windowID;//視窗ID
	UserType windowType=null;//視窗型別
	String windowTypeName="";//視窗型別名字
	String userTypeName="";//客戶型別名字
	int maxRandom=Constants.MAX_BUSINESS_TIME-Constants.MIN_BUSINESS_TIME;//業務隨機時間
	
	
	public ServiceWindow(){}
	public ServiceWindow(int windowID,UserType windowType){
		this.windowID=windowID;
		this.windowType=windowType;
		ExecutorService pool= Executors.newSingleThreadExecutor();
		pool.execute(
				
				new Runnable(){
					public void run(){
						while(true){
							windowTypeName=NumberManager.getInstance().getUserType(ServiceWindow.this.windowType);
							if(NumberManager.getInstance().userNumbeList.size()==0 && NumberManager.getInstance().userExpressNumbeList.size()==0 && NumberManager.getInstance().userVipNumbeList.size()==0){
								System.out.println("當前還沒有客戶前來辦理業務!"+ServiceWindow.this.windowID+"號"+windowTypeName+"視窗狀態空閒!");
								
								try {
									Thread.sleep(10000);//休息10秒鐘
								} catch (InterruptedException e) {
									// TODO Auto-generated catch block
									e.printStackTrace();
								}
							}else{
								User user=NumberManager.getInstance().remove(ServiceWindow.this.windowID,ServiceWindow.this.windowType);
								if(user!=null){
									userTypeName=NumberManager.getInstance().getUserType(user.getUserType());
									int businessTime=0;
									try {
										switch (user.getUserType()) {
										case COMMONUSER:
											//普通客戶辦理業務需要用時,在最大值和最小值之間
											businessTime=new Random().nextInt(ServiceWindow.this.maxRandom)+1+Constants.MIN_BUSINESS_TIME;
											Thread.sleep(businessTime);
											break;
										case EXPRESSUSER:
											//快速客戶辦理月舞的速度最快
											businessTime=Constants.MIN_BUSINESS_TIME;
											Thread.sleep(businessTime);
											break;
										case VIPUSER:
											//VIP客戶辦理業務需要用時,在最大值和最小值之間
											businessTime=new Random().nextInt(ServiceWindow.this.maxRandom)+1+Constants.MIN_BUSINESS_TIME;
											Thread.sleep(businessTime);
											break;
										default:
											break;
										}
										System.out.println(user.getNumber()+"號"+userTypeName+"客戶在"+ServiceWindow.this.windowID+"號"+windowTypeName+"視窗辦理完業務啦!用時:"+businessTime/1000+"."+businessTime%1000+"秒");
										
										System.out.println("業務辦理完成休息5秒!");
										Thread.sleep(5000);
										
									} catch (InterruptedException e) {
										// TODO Auto-generated catch block
										e.printStackTrace();
									}
									
								}
								
							}
						}
						
					}
				
				}
				
		);
	}
}
號碼產生管理器:

為客戶產生排隊號碼,當視窗索要號碼時,把號碼給視窗後,刪除本號碼。每隔一段時間自動產生客戶和號碼。我這裡為了檢視系統處理很多各種各樣的客戶會不會出現bug,設定了每一秒產生一個客戶。

package com.itcast;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;





public class NumberManager {
	private static NumberManager numberManager=null;
	
	List<User> userNumbeList=new ArrayList<User>();//普通號碼的客戶列表
	List<User> userExpressNumbeList=new ArrayList<User>();//快速號碼的客戶列表
	List<User> userVipNumbeList=new ArrayList<User>();//VIP號碼的客戶列表
	
	static int number=0;
	static int expressNumber=0;
	static int vipNumber=0;
	public  synchronized void add(User user){
		 userNumbeList.add(user);
	}
	public  synchronized User remove(int windowID,UserType windowType){

		User user=null;
		switch (windowType) {
			case COMMONUSER:
				if(userNumbeList.size()!=0){
					user=userNumbeList.remove(0);
					System.out.println("請"+user.getNumber()+"號普通客戶到"+windowID+"號普通視窗辦理業務!"+windowID+"號普通視窗開始為"+user.getNumber()+"號普通客戶辦理業務。");
					System.out.println();
				}
				return user;
			case EXPRESSUSER:
				if(userExpressNumbeList.size()!=0){
					//如果快速客戶列表有客戶的話執行快速叫號程式
					user=userExpressNumbeList.remove(0);
					System.out.println("請"+user.getNumber()+"號快速客戶到"+windowID+"號快速視窗辦理業務!"+windowID+"號快速視窗開始為"+user.getNumber()+"號快速客戶辦理業務。");
					System.out.println();
				}else{
					//如果快速客戶列表沒有快速客戶就檢視普通客戶列表有沒有客戶
					if(userNumbeList.size()!=0){
						//如果有就叫號普通客戶到快速視窗進行業務操作
						user=userNumbeList.remove(0);
						
						System.out.println("當前"+windowID+"號快速客戶視窗無人,請"+user.getNumber()+"號普通客戶到"+windowID+"號快速視窗辦理業務!"+windowID+"號快速視窗開始為"+user.getNumber()+"號普通客戶辦理業務。");
						System.out.println();
					}
				}
				return user;
			case VIPUSER:
				if(userVipNumbeList.size()!=0){
					//如果VIP客戶列表有客戶的話執行VIP叫號程式
					user=userVipNumbeList.remove(0);
						System.out.println("請"+user.getNumber()+"號VIP客戶到"+windowID+"號VIP視窗辦理業務!"+windowID+"號VIP視窗開始為"+user.getNumber()+"號VIP客戶辦理業務。");
						System.out.println();
					
				}else{
					//如果VIP客戶列表沒有快速客戶就檢視普通客戶列表有沒有客戶
					if(userNumbeList.size()!=0){
						//如果有就叫號普通客戶到VIP視窗進行業務操作
						user=userNumbeList.remove(0);
						System.out.println("當前"+windowID+"號VIP客戶視窗無人,請"+user.getNumber()+"號普通客戶到"+windowID+"號VIP視窗辦理業務!"+windowID+"號VIP視窗開始為"+user.getNumber()+"號普通客戶辦理業務。");
						System.out.println();
					}
				}
				
				
				return user;
	
			default:
				break;
		}
		return user;
		
		
	}
	
	
	private NumberManager(){
		ExecutorService pool= Executors.newSingleThreadExecutor();
		pool.execute(
			new Runnable(){
				public void run(){
					while(true){
						try {
							//(new Random().nextInt(10)+1)*1000
							Thread.sleep(1000);//隨機(1-10)秒後產生一個客戶
						} catch (InterruptedException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
						int random =new Random().nextInt(10)+1;
						switch (random) {
						case 1:
						case 2:
						case 3:
						case 4:
						case 5:
						case 6:
							number++;
							System.out.println("歡迎第"+number+"位普通客戶來到黑馬銀行!");
							userNumbeList.add(new User(UserType.COMMONUSER,number));
							break;
						case 7:
						case 8:
						case 9:
							expressNumber++;
							System.out.println("歡迎第"+expressNumber+"位快速客戶來到黑馬銀行!");
							userExpressNumbeList.add(new User(UserType.EXPRESSUSER,expressNumber));
							break;
						case 10:
							vipNumber++;
							System.out.println("歡迎第"+vipNumber+"位VIP客戶來到黑馬銀行!");
							userVipNumbeList.add(new User(UserType.VIPUSER,vipNumber));
							break;
						default:
							break;
						}

						
						
					}
				
			}
			}
		);
	}
	
	
	
	public static  NumberManager getInstance(){
		if (numberManager==null){
			//新增鎖,使多執行緒同步更安全
			synchronized(NumberManager.class){
				if (numberManager==null){
					numberManager=new NumberManager();
					
				}
			}
		}
		return numberManager;
	}
	public String getUserType(UserType userType){
		String userTypeName="";
		switch (userType) {
		case COMMONUSER:
			userTypeName="普通";
			return userTypeName;
		case EXPRESSUSER:
			userTypeName="快速";
			return userTypeName;
		case VIPUSER:
			userTypeName="VIP";
			return userTypeName;

		default:
			break;
		}
		return userTypeName;
	}
	
}

視窗為客戶辦理業務的時間範圍Constants:

這是一個配置檔案類。以後只需要在這個類中修改時間就能控制辦理業務時間範圍。

1000等於1秒,最小值不得小於1000;

package com.itcast;

public class Constants {
	//業務所用的時間最大值和最小值
	public static int MAX_BUSINESS_TIME=10000;
	public static int MIN_BUSINESS_TIME=3000;
	
	
}

使用者類:User

封裝了客戶的一些基本資訊。便於操作。

package com.itcast;

public class User {
	private String name="王瑞亞";
	private int  number;
	private UserType userType;
	public UserType getUserType() {
		return userType;
	}
	public void setUserType(UserType userType) {
		this.userType = userType;
	}
	public int getNumber() {
		return number;
	}
	public void setNumber(int number) {
		this.number = number;
	}
	
	public String getName() {
		return name;
	}
	User(){}
	User(UserType userType,int  number){
		this.userType=userType;
		this.number=number;
	}
	
}

視窗型別和客戶型別列舉類UserType:
package com.itcast;

public enum UserType {
	COMMONUSER,EXPRESSUSER,VIPUSER;
	
}
main方法類,程式開始的地方BankMain:
package com.itcast;

public class BankMain {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		NumberManager nm=NumberManager.getInstance();
		for(int i=1;i<5;i++){
			//迴圈建立四個普通視窗
			new ServiceWindow(i,UserType.COMMONUSER);
		}
		
		new ServiceWindow(1,UserType.EXPRESSUSER);//建立一個快速客戶視窗
		new ServiceWindow(1,UserType.VIPUSER);//建立一個VIP視窗
	}

}


專案總結:

用了一個晚上思考如果實現邏輯和架構,第二天上午寫程式,下午修改bug,我還沒有達到張老師一氣呵成的功力!還需努力!

這是一個模擬現實中銀行業務邏輯的一個小程式,這個專案培養了我對專案需求的分析,以及對專案的構架。一個程式不是功能都完成了就算寫完了,還要審視程式的架構,是否是一個健壯的系統,是否易於擴充套件,是否處理了各種突發情況,程式是否人性化等等。這樣才能不斷的成長,從運用自己的java技術到合理的運用達到最大好處,這是一個轉變。現在我還沒有能力拿到一個專案就能馬上構架好這個專案的框架。我給自己定了一個職業規劃:三年內達到專案經理的水平,當上總監,或創業或當一名老師(由於對張孝祥老師的敬佩,決定跟隨他)。

接下來我打算花功夫學習學習軟體的設計和資料結構,從而設計完美的程式碼。

閱盡天下程式碼,心中自然有碼。

下面把控制檯輸出結果放出來,本人測試很多遍了目前沒有發現bug,大家可以複製程式碼在自己機器執行試試,如果有錯誤的話請大家聯絡我在修改。我的QQ1659881336.謝謝啦!

當前還沒有客戶前來辦理業務!1號普通視窗狀態空閒!
當前還沒有客戶前來辦理業務!2號普通視窗狀態空閒!
當前還沒有客戶前來辦理業務!4號普通視窗狀態空閒!
當前還沒有客戶前來辦理業務!3號普通視窗狀態空閒!
當前還沒有客戶前來辦理業務!1號快速視窗狀態空閒!
當前還沒有客戶前來辦理業務!1號VIP視窗狀態空閒!
歡迎第1位普通客戶來到黑馬銀行!
歡迎第2位普通客戶來到黑馬銀行!
歡迎第3位普通客戶來到黑馬銀行!
歡迎第1位快速客戶來到黑馬銀行!
歡迎第4位普通客戶來到黑馬銀行!
歡迎第5位普通客戶來到黑馬銀行!
歡迎第6位普通客戶來到黑馬銀行!
歡迎第1位VIP客戶來到黑馬銀行!
歡迎第7位普通客戶來到黑馬銀行!
歡迎第8位普通客戶來到黑馬銀行!
請1號普通客戶到1號普通視窗辦理業務!1號普通視窗開始為1號普通客戶辦理業務。


請2號普通客戶到2號普通視窗辦理業務!2號普通視窗開始為2號普通客戶辦理業務。


請3號普通客戶到4號普通視窗辦理業務!4號普通視窗開始為3號普通客戶辦理業務。


請4號普通客戶到3號普通視窗辦理業務!3號普通視窗開始為4號普通客戶辦理業務。


請1號VIP客戶到1號VIP視窗辦理業務!1號VIP視窗開始為1號VIP客戶辦理業務。


請1號快速客戶到1號快速視窗辦理業務!1號快速視窗開始為1號快速客戶辦理業務。


歡迎第9位普通客戶來到黑馬銀行!
歡迎第10位普通客戶來到黑馬銀行!
歡迎第2位快速客戶來到黑馬銀行!
1號快速客戶在1號快速視窗辦理完業務啦!用時:3.0秒
業務辦理完成休息5秒!
4號普通客戶在3號普通視窗辦理完業務啦!用時:3.887秒
業務辦理完成休息5秒!
歡迎第3位快速客戶來到黑馬銀行!
3號普通客戶在4號普通視窗辦理完業務啦!用時:4.80秒
業務辦理完成休息5秒!
歡迎第2位VIP客戶來到黑馬銀行!
歡迎第11位普通客戶來到黑馬銀行!
1號普通客戶在1號普通視窗辦理完業務啦!用時:6.900秒
業務辦理完成休息5秒!
歡迎第12位普通客戶來到黑馬銀行!
1號VIP客戶在1號VIP視窗辦理完業務啦!用時:7.424秒
業務辦理完成休息5秒!
歡迎第4位快速客戶來到黑馬銀行!
請2號快速客戶到1號快速視窗辦理業務!1號快速視窗開始為2號快速客戶辦理業務。


請5號普通客戶到3號普通視窗辦理業務!3號普通視窗開始為5號普通客戶辦理業務。


歡迎第5位快速客戶來到黑馬銀行!
請6號普通客戶到4號普通視窗辦理業務!4號普通視窗開始為6號普通客戶辦理業務。


2號普通客戶在2號普通視窗辦理完業務啦!用時:9.396秒
業務辦理完成休息5秒!
歡迎第3位VIP客戶來到黑馬銀行!
歡迎第6位快速客戶來到黑馬銀行!
2號快速客戶在1號快速視窗辦理完業務啦!用時:3.0秒
業務辦理完成休息5秒!
請7號普通客戶到1號普通視窗辦理業務!1號普通視窗開始為7號普通客戶辦理業務。


歡迎第7位快速客戶來到黑馬銀行!
請2號VIP客戶到1號VIP視窗辦理業務!1號VIP視窗開始為2號VIP客戶辦理業務。


5號普通客戶在3號普通視窗辦理完業務啦!用時:3.999秒
業務辦理完成休息5秒!
歡迎第13位普通客戶來到黑馬銀行!
歡迎第4位VIP客戶來到黑馬銀行!
請8號普通客戶到2號普通視窗辦理業務!2號普通視窗開始為8號普通客戶辦理業務。


歡迎第5位VIP客戶來到黑馬銀行!
歡迎第14位普通客戶來到黑馬銀行!
請3號快速客戶到1號快速視窗辦理業務!1號快速視窗開始為3號快速客戶辦理業務。


2號VIP客戶在1號VIP視窗辦理完業務啦!用時:4.398秒
業務辦理完成休息5秒!
歡迎第15位普通客戶來到黑馬銀行!
6號普通客戶在4號普通視窗辦理完業務啦!用時:8.402秒
業務辦理完成休息5秒!
請9號普通客戶到3號普通視窗辦理業務!3號普通視窗開始為9號普通客戶辦理業務。


歡迎第8位快速客戶來到黑馬銀行!
8號普通客戶在2號普通視窗辦理完業務啦!用時:3.836秒
業務辦理完成休息5秒!
歡迎第16位普通客戶來到黑馬銀行!
3號快速客戶在1號快速視窗辦理完業務啦!用時:3.0秒
業務辦理完成休息5秒!
7號普通客戶在1號普通視窗辦理完業務啦!用時:7.140秒
業務辦理完成休息5秒!
歡迎第17位普通客戶來到黑馬銀行!
歡迎第18位普通客戶來到黑馬銀行!
請3號VIP客戶到1號VIP視窗辦理業務!1號VIP視窗開始為3號VIP客戶辦理業務。


歡迎第19位普通客戶來到黑馬銀行!
請10號普通客戶到4號普通視窗辦理業務!4號普通視窗開始為10號普通客戶辦理業務。


歡迎第6位VIP客戶來到黑馬銀行!
請11號普通客戶到2號普通視窗辦理業務!2號普通視窗開始為11號普通客戶辦理業務。


歡迎第20位普通客戶來到黑馬銀行!
請4號快速客戶到1號快速視窗辦理業務!1號快速視窗開始為4號快速客戶辦理業務。


請12號普通客戶到1號普通視窗辦理業務!1號普通視窗開始為12號普通客戶辦理業務。