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

黑马程序员--银行业务调度系统分析讲解及实现

2013-09-27 16:55 453 查看
----------------------
ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------

银行业务调度系统

需求:

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

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

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

3、异步随机生成各种类型的客户,生成各类型用户的概率比例为:

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

4、客户办理业务所需时间有最大值和最小值,在该范围内随机设定每个VIP客户以及普通客户办理业务所需的时间,

快速客户办理业务所需时间为最小值(提示:办理业务的过程可通过线程Sleep的方式模拟)。

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

6、当VIP(6号)窗口和快速业务(5号)窗口没有客户等待办理业务的时候,这两个窗口可以处理普通客户的业务,

而一旦有对应的客户等待办理业务的时候,则优先处理对应客户的业务。

7、随机生成客户时间间隔以及业务办理时间最大值和最小值自定,可以设置。

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

需求分析:

面向对象的分析和设计

1、有三种对应类型的客户:VIP客户,普通客户,快速客户。异步随机生成各种类型的客户,各类型客户在其对应窗口按顺序依次办理业务。

分析:

(1)三种类型的客户需要一个取号机产生,该取号机只有一个,因此应该设计为单例模式。

(2)而这三类号码的生成机制相同,因此可以封装为一个内部类。即号码管理类,负责管理号码,包括生成号码、取号码。

(3)取号机取出的号码根据客户类型可以分为三类,VIP客户,普通客户,快速客户。即生成三类号码管理器。

因此,应该设计以下两个类:

号码管理器:用于管理所有号码,包括生成号码、取号。可以是取号机的内部类。

取号机:用于生成不同类型的号码管理器。单例模式。

2、 银行内有6个业务窗口,1 - 4号窗口为普通窗口,5号窗口为快速窗口,6号窗口为VIP窗口。

分析:

(1)本质上所有窗口都是一样的,只不过按上了不同的标识。不同的窗口就是不同的实例对象。

(2)服务窗口要拥有设置窗口类型的行为,设置窗口号的行为,以及获取窗口类型的行为,开启服务的行为。

(3)开启服务的同时,应该能够根据不同的实例对象类型来进行不同的服务。

(4)其中的三种类型可以设计为enum。

因此:应该设计一个类:

服务窗口:用于生成不同类型的实例对象,并根据不同的类型来进行不同的服务。

1、窗口类型、窗口号

2、初始化时就应该初始化窗口类型。

3、设置窗口号、设置窗口类型

4、服务窗口有三种服务方法,分别对应三种类型的酷客户

3、需要一个主类来启动整个调度系统

(1)该类中声明4个普通窗口,分别设置类型,设置窗口号,并开启服务。

(2)分别产生1个快速窗口和1个VIP窗口,设置类型,并开启服务。

(3)生成三个模拟客户取号的过程,按比例在一定期限内,随机产生不同类型的客户。

系统实现代码:

一、取号器 NumMachine

package com.heima.exam.bank;

import java.util.*;

/**
* 取号器
* 用于生成不同类型的号码管理器
*
* 1、一般一个银行中只有一个取号器,因此设计为单利模式
* 2、取号器中有一个号码生成器,因此设计一个内部类:号码生成器。
* 3、号码生成器在实例化时即指明是哪一种类型的生成器
* 4、号码生成器管理号码,包括生成好码、取号。
*
* @author zhangyunfei
*
*/
public class NumMachine {

//将取号机设置为单例模式
private static NumMachine numMachine = new NumMachine();
private NumMachine(){}
public static NumMachine getInstance(){
return numMachine;
}
//分别声明三种类型的号码生成器
private NumManager commonNumMagager = new NumManager(CustomerType.COMMON);
private NumManager expressNumMagager = new NumManager(CustomerType.EXPRESS);
private NumManager vipNumMagager = new NumManager(CustomerType.VIP);
//分别生成三中类型号码生成器的获取方法
public NumManager getCommonNumMagager() {
return commonNumMagager;
}
public NumManager getExpressNumMagager() {
return expressNumMagager;
}
public NumManager getVipNumMagager() {
return vipNumMagager;
}
/**
* 号码管理器。
* 用于管理所有号码,包括生成号码、取号。是取号机的内部类。
* @author zhangyunfei
*
*/
class NumManager{
private List<Integer> numList = new LinkedList<Integer>();	//一个存储号码的集合
private Integer num = 0;					//模拟顾客的数量
private CustomerType numType = null;		//该号码产生器的类型

//初始化时即定义该号码产生器实例的类型
public NumManager(CustomerType type){
this.numType = type;
}
//来一个新的顾客,在等待服务。共享同一个集合,同步
public synchronized Integer createNum(){
numList.add(++num);
System.out.println(numType + "客户_" + num + "正在等待服务...");
return num;
}
//取号。如果该实例类型的客户存在,则返回最前边的客户号,否则返回null。共享同一个集合,同步
public synchronized Integer fetchNum(){
if(!numList.isEmpty()){
return numList.remove(0);
}
return null;
}
}

}


二、服务窗口 ServiceWindow

package com.heima.exam.bank;

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

/**
* 服务窗口类
* 用于生成不同类型的实例对象,并根据不同的类型来进行不同的服务。
* 成员变量:窗口类型、窗口号、该窗口是否开启服务
* 成员方法:开启服务、不同的服务方法、关闭服务等
*
* @author zhangyunfei
*
*/
public class ServiceWindow {
//服务窗口的类型,默认为普通类型
private CustomerType windowType = null;
//服务窗口号,默认为1号
private int windowNum = 1;
//该窗口是否开启服务
private boolean isService = false;

//初始化窗口时就应该初始化窗口类型
public ServiceWindow(CustomerType windowType){
this.windowType = windowType;
}
//开启服务,根据不同的窗口类型,进行不同的服务
public void start(){
this.isService = true;	//开启服务
Executors.newSingleThreadExecutor().execute(
new Runnable(){
@Override
public void run(){
switch(windowType){
case COMMON:
while(isService){
commonService();	//开启普通客户服务窗口
}
break;
case EXPRESS:
while(isService){
expressService();	//开启快速客户服务窗口
}
break;
case VIP:
while(isService){
vipService();		//开启VIP客户服务窗口
}
break;

}
}
});
}
//下班了
public void closeService(){
this.isService = false;
System.out.println(this.windowNum+this.windowNum + "下班了!");
}

/*
* 定义三种服务方法
*/
//普通服务方法。1、首先叫号 2、判断是否有号。有号则服务,无号则等待1秒钟 3、依次循环
public void commonService(){
//1、叫号
System.out.println(this.windowType+"_"+this.windowNum + "正在叫普通号...");
Integer num = NumMachine.getInstance().getCommonNumMagager().fetchNum();
//2、判断是否有号
if(num != null){//有号
//开始服务
System.out.println(this.windowType+"_"+this.windowNum + " 窗口正在为 " +"普通号_"+num + "服务>>>>>");
int subTime = Constants.MAX_SERVICE_TIME - Constants.MIN_SERVICE_TIME;
int comServiceTime = new Random().nextInt(subTime) + 1 + Constants.MIN_SERVICE_TIME;
try {
Thread.sleep(comServiceTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(this.windowType+"_"+this.windowNum + " 窗口为 " + this.windowType+"_"+num + "服务over,总耗时为"+comServiceTime/1000 + "s。欢迎下次光临!");
}else{//无号
System.out.println(this.windowType+"_"+this.windowNum + " 窗口没有取到普通号,等待1s");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//快速服务方法。1、首先叫号 2、判断是否有号。有号则服务;无号则叫普通号,为普通号服务 3、依次循环
public void expressService(){
System.out.println(this.windowType+"_"+this.windowNum + "正在叫快速号...");
//1、叫号
Integer num = NumMachine.getInstance().getExpressNumMagager().fetchNum();
//2、判断是否有号
if(num != null){//有号
//开始服务
System.out.println(this.windowType+"_"+this.windowNum + " 窗口正在为 " + "快速号_"+num + "服务>>>>>");
int comServiceTime = Constants.MIN_SERVICE_TIME;	//快速号的服务时间为最小值
try {
Thread.sleep(comServiceTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(this.windowType+"_"+this.windowNum + " 窗口为 " + "快速号_"+num + "服务over,总耗时为"+comServiceTime/1000 + "s。欢迎下次光临!");
}else{//无号
System.out.println(this.windowType+"_"+this.windowNum + " 窗口没有取到快速号,开始叫普通号");
commonService();					//快速窗口优先为快速客户服务,没有则为普通客户服务
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//VIP服务方法。1、首先叫号 2、判断是否有号。有号则服务;无号则叫普通号,为普通号服务 3、依次循环
public void vipService(){
System.out.println(this.windowType+"_"+this.windowNum + "正在叫VIP号...");
//1、叫号
Integer num = NumMachine.getInstance().getCommonNumMagager().fetchNum();
//2、判断是否有号
if(num != null){//有号
//开始服务
System.out.println(this.windowType+"_"+this.windowNum + " 窗口正在为 " + "VIP_"+num + "服务>>>>>");
int subTime = Constants.MAX_SERVICE_TIME - Constants.MIN_SERVICE_TIME;
int comServiceTime = new Random().nextInt(subTime) + 1 + Constants.MIN_SERVICE_TIME;
try {
Thread.sleep(comServiceTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(this.windowType+"_"+this.windowNum + " 窗口为 " +"VIP_"+num + "服务over,总耗时为"+comServiceTime/1000 + "s。欢迎下次光临!");
}else{//无号
System.out.println(this.windowType+"_"+this.windowNum + " 窗口没有取到VIP号,则叫普通号");
commonService();					//VIP窗口优先为VIP客户服务,没有则为普通客户服务
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

public CustomerType getWindowType() {
return windowType;
}
public void setWindowType(CustomerType windowType) {
this.windowType = windowType;
}
public int getWindowNum() {
return windowNum;
}
public void setWindowNum(int windowNum) {
this.windowNum = windowNum;
}
}


三、客户类型 CustomType(enum类型)

package com.heima.exam.bank;

/**
* 客户类型
*
* @author zhangyunfei
*
*/
public enum CustomerType {
COMMON,EXPRESS,VIP;
//覆盖toString()方法,直接打印时以友好的字符串形式出现
@Override
public String toString(){
switch(this){
case COMMON:
return "普通";
case EXPRESS:
return "快速";
case VIP:
return name();
}
return null;
}
}


四、静态值Constants

package com.heima.exam.bank;

public class Constants {
public static int MAX_SERVICE_TIME = 10000;//最大的服务时间为10s
public static int MIN_SERVICE_TIME = 1000;//最小的服务时间为1s

}


五、主方法类 MainClass

package com.heima.exam.bank;

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

/**
* 主方法类
* 1、产生服务窗口
* 2、模拟客户取号
*
* @author zhangyunfei
*
*/
public class MainClass {

public static void main(String[] args) {
/**
* 产生服务窗口,并开启
*/
//产生4个普通窗口
for(int i = 1; i < 5; i++){
ServiceWindow comWindow = new ServiceWindow(CustomerType.COMMON);	//产生普通窗口
comWindow.setWindowNum(i);	//设置窗口号
comWindow.start();
}
//产生1个快速窗口
ServiceWindow expressWindow = new ServiceWindow(CustomerType.EXPRESS);	//产生快速窗口
expressWindow.start();

//产生1个VIP窗口
ServiceWindow vipWindow = new ServiceWindow(CustomerType.VIP);			//产生VIP窗口
vipWindow.start();

/**
* 模拟客户到取号机取号
*/
//普通客户取号
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
new Runnable(){
@Override
public void run(){
NumMachine.getInstance().getCommonNumMagager().createNum();//普通客户取号
}
},
0,
1,
TimeUnit.SECONDS);
//快速客户取号
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
new Runnable(){
@Override
public void run(){
NumMachine.getInstance().getExpressNumMagager().createNum();//快速客户取号
}
},
0,
2,
TimeUnit.SECONDS);
//VIP客户取号
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
new Runnable(){
@Override
public void run(){
NumMachine.getInstance().getVipNumMagager().createNum();//VIP客户取号
}
},
0,
6,
TimeUnit.SECONDS);
}

}


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