您的位置:首页 > 职场人生

黑马程序员_银行业务调度系统

2013-12-14 21:34 351 查看
------- android培训java培训、期待与您交流!
----------
一、银行业务调度需求分析

模拟实现银行业务调度系统逻辑,具体需求如下:

1)、银行内有6个业务窗口,1~4号窗口为普通窗口,5号窗口为快速窗口,6号窗口为VIP窗口;

2)、有3中对应类型的客户:VIP客户、普通客户、快速客户(办理如交水电费、电话费之类业务的客户);

3)、异步随机生成各类型的客户,生成各类型用户的概率比例为:VIP客户:普通客户:快速客户 = 1:6:3;

4)、客户办理业务所需时间有最大值和最小值,在该范围内随机设定每个VIP客户以及普通客户办理业务所需的时间,快速客户办理业务所需时间为最小值(提示:办理业务的过程可以通过线程sleep的方式模拟);

5)、各类客户在其对应窗口按顺序依次办理业务;

6)、当VIP窗口和快速业务窗口没有客户等待办理业务的时候,这两个窗口可以处理普通客户的业务,而一旦有对应的客户等待办理业务的时候,则优先处理对应客户的业务;

7)、随机生成客户时间间隔及业务办理时间最大值和最小值;

8)、不要求实现GUI,只考虑系统逻辑实现,可以通过log方式展现程序运行结果。

二、系统分析及设计

1、系统分析

通过分析我们知道银行的客户是使用取号机获取对应要服务的客户的号码来表示的,所以我们可是实现一个取号机不断地生成号码,就相当于随机生成客户了。客户分为三种:普通客户、VIP客户和快速客户,每类客户的号码都是独立的。所以该系统就得设计三个与之对应的号码管理器,分别来产生对应的客户号码。而这三个号码管理器又是同同一个取号机来进行管理的,所以我们就得把取号机设计成单例模式。

各个用户在对应的窗口依次排队等待业务办理,也就是与之对应的窗口在依次叫号。通过分析我们就可以得到该系统可以由以下三个类来组成:取号机(NumberMachine)、号码管理器(NumberManager)、服务窗口(ServiceWindow)。通过这一层一层关系的分析我们可以得到如下的类图:

(注:由于取号机始终只有一个,所以设计成单例模式,所以getInstance()方法有下划线)



2、各类的设计

1)、NumberManager类

该类需要定义需要定义一个产生新号码的方法和一个获取需要被服务的号码,该类中还需要定义一个从1开始产生新号码的变量,以及一个存储这些号码的集合。在产生新号码的方法中,每有一个新号码产生,就将这些号码存储到集合中。在获取号码的方法中,每次都得将先进入集合的号码取出(即可以通过集合的移除方法来实现)并对其进行业务办理。由于两个方法会操作集合中的共同数据,所以为了安全起见,这两个方法需要加上锁来进行同步。

代码体现:

package com.itheima.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 generateNewNumber(){
queueNumber.add(lastNumber);
return lastNumber++;
}

public synchronized Integer fetchServiceNumber(){
Integer number = null;
if(queueNumber.size() > 0){
number =queueNumber.remove(0);
}
return number;
}
}


2)、NumberMachine类

由于取号机中有3个号码管理器,所以该类中需要定义3个号码管理器并有获取各自与之对应的号码的方法。因为NumberMachine始终只能有一个对象,所以还得设计成单例模式。

代码体现:

package com.itheima.bank;

public class NumberMachine {
private NumberManager commonManager = new NumberManager(); //创建3个对应的号码管理器;
private NumberManager vipManager = new NumberManager();
private NumberManager expressManager = new NumberManager();

public NumberManager getCommonManager() {
return commonManager;
}
public NumberManager getVipManager() {
return vipManager;
}
public NumberManager getExpressManager() {
return expressManager;
}

private NumberMachine(){}
private static NumberMachine instance = new NumberMachine();
public static NumberMachine getInstance(){          //通过单例设计模式来保证对象的唯一性;
return instance;
}

}


3)、ServiceWindow类

该方法中需要定义一个开始start方法来实现不断叫号的功能。由于该窗口中需要服务不同类型的客户,所以我们又可以定义一个枚举来将各种类型的客户存储在其中。在这3个方法中分别对各自的客户进行服务。普通服务中,当有客户排队等待时,打印出普通窗口中的几号窗口在为排队的几号客户服务,并使用随机数计算出服务该客户使用了多长时间(时间范围为在1s~10s之间的随机数);当没有客户时,变休息1s,再继续回去寻找是否存在客户;快速窗服务中,当有客户时,为客户提供服务并提供服务时间,当没有客户服务时,看普通窗口有没有客户,如果普通窗口还有客户,则为普通窗口的客户服务;VIP服务与快速服务的相似。

代码体现:

package com.itheima.bank;

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

public class ServiceWindow {
private CostumerType type = CostumerType.COMMON;
private int windowID = 1;

public void setType(CostumerType type) {
this.type = type;
}
public void setWindowID(int windowID) {
this.windowID = windowID;
}

public void start(){
Executors.newSingleThreadExecutor().execute(new Runnable(){
public void run() {
while(true){
switch(type){
case COMMON:
commonService();
break;
case EXPRESS:
expressService();
break;
case VIP:
vipService();
break;
}
}
}
});
}

private void commonService() {
String windowName = "第" + windowID + "号" + type +"窗口";
Integer number = NumberMachine.getInstance().getCommonManager().fetchServiceNumber();
System.out.println(windowName + "正在获取任务...");
if(number != null){
System.out.println(windowName + "为第" + number + "个普通客户服务!!!");
long beginTime = System.currentTimeMillis();
int maxRand = Constants.MAX_SERVICE_TIME - Constants.MIN_SERVICE_TIME; //9000;
long serverTime = new Random().nextInt(maxRand) + 1 + Constants.MIN_SERVICE_TIME;
try {
Thread.sleep(serverTime);
} catch (InterruptedException e) {
e.p
b47d
rintStackTrace();
}
long costTime = System.currentTimeMillis() - beginTime;
System.out.println(windowName + "为第" + number + "个普通客户完成服务,耗时" + costTime/1000 + "秒");
}else{
System.out.println(windowName +"没有取到任务!先休息1秒。");
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){
System.out.println(windowName + "为第" + number + "个" + type+ "客户服务!!!");
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();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

private void vipService() {
String windowName = "第" + windowID + "号" + type +"窗口";
Integer number = NumberMachine.getInstance().getVipManager().fetchServiceNumber();
System.out.println(windowName + "正在获取任务...");
if(number != null){
System.out.println(windowName + "为第" + number + "个" + type+ "客户服务!!!");
long beginTime = System.currentTimeMillis();
int maxRand = Constants.MAX_SERVICE_TIME - Constants.MIN_SERVICE_TIME; //9000;
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();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}


4)、CostumerType类

该类为枚举类,该类中列举了三种客户类型。并重写了toString方法,返回各种客户类型的中文名称。

代码体现:

package com.itheima.bank;

public enum CostumerType {
COMMON,EXPRESS,VIP;

public String toString(){
switch(this){
case COMMON:
return "普通";
case EXPRESS:
return "快速";
case VIP:
return name();
}
return null;
}
}


5)、常量类Constants

该类中定义了服务时间的最大值和最小值,以及普通客户来办理业务的频率时间。

代码体现:

package com.itheima.bank;

public class Constants {
public static int MAX_SERVICE_TIME = 10000;
public static int MIN_SERVICE_TIME = 1000;
public static int COMMON_CONSTUMER_INTERVIAL_TIME = 1;
}


6)、测试类MainClass

该类中需要创建4个普通窗、1个快速窗口和1个VIP窗口。还需要创建3个线程来模拟3中客户类型来办理事务,通过控制时间来模拟各种类型客户的比例。

代码体现:

package com.itheima.bank;

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

public class MainClass {

public static void main(String[] args) {
for(int i=1; i<5; i++){
ServiceWindow commonWindow = new ServiceWindow();
commonWindow.setWindowID(i);
commonWindow.start();
}

ServiceWindow expressWindow = new ServiceWindow();
expressWindow.setType(CostumerType.EXPRESS);
expressWindow.setWindowID(5);
expressWindow.start();

ServiceWindow vipWindow = new ServiceWindow();
vipWindow.setType(CostumerType.VIP);
vipWindow.setWindowID(6);
vipWindow.start();

Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
new Runnable(){
public void run() {
Integer number = NumberMachine.getInstance().getCommonManager().generateNewNumber();
System.out.println(number + "号普通客户等待服务!!!");
}
},
0,
Constants.COMMON_CONSTUMER_INTERVIAL_TIME,
TimeUnit.SECONDS);

Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
new Runnable(){
public void run() {
Integer number = NumberMachine.getInstance().getExpressManager().generateNewNumber();
System.out.println(number + "号快速客户等待服务!!!");
}
},
0,
Constants.COMMON_CONSTUMER_INTERVIAL_TIME * 2,
TimeUnit.SECONDS);

Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
new Runnable(){
public void run() {
Integer number = NumberMachine.getInstance().getVipManager().generateNewNumber();
System.out.println(number + "号VIP客户等待服务!!!");
}
},
0,
Constants.COMMON_CONSTUMER_INTERVIAL_TIME * 6,
TimeUnit.SECONDS);
}
}


-------
android培训、java培训、期待与您交流! ----------
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: