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

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

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

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

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

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

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

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

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

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

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

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

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

一、面向对象的分析与设计

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

a.通过对银行服务管理系统的了解,每一个客户其实就是由银行的一个“取号机器”产生号码的方式来表示的,因此这就需要一个号码管理器对象,让这个对象不断地产生号码,就等于随机生成了客户。

b.由于有三类客户,而每类客户的号码编排都是完全独立的,所以本系统一共要产生三个号码管理器对象,各自管理一类用户的排队号码。这三个号码管理器对象统一由一个号码机器进行管理,这个号码机器在整个系统中始终只能有一个,所以,它要被设计成单例。

2、各类型客户在其对应窗口按顺序依次办理业务,准确地说,应该是窗口依次叫号。

各个窗口怎么知道该叫哪一个号了呢?它一定是问的相应的号码管理器,即服务窗口每次找号码管理器获取当前要被服务的号码。

二、通过分析,可以推算出一下类图:



1、NumberMachine类

1.定义三个成员变量分别指向三个NumberManager对象,分别表示普通、快速和VIP客户的号码管理器,并分别定义三个对应的方法来返回这三个NumberManager对象。

2.由于NumberMachine分别控制着三个对象,而其三个对象共享一个数据,因此这里需要将NumberMachine类设计成单例。

2、NumberManager类

1.定义一个用于存储上一个客户号码的成员变量和用于存储所有等待服务的客户号码的队列集合。

2.定义一个产生新号码的方法和获取马上要为之服务的号码的方法,这两个方法被不同的线程操作了相同的数据,所以要进行同步synchronized。

3、ServiceWindow类

1.定义一个start方法,内部启动一个线程,根据服务窗口的类别分别循环调用三个不同的方法。

2.定义三个方法分别对三种客户进行服务,为了观察运行效果,应详细打印出其中的详细信息。

4、CustomerType枚举类

1.系统中有三种类型的客户,所以定义一个枚举类,其中定义三个成员分别表示三种类型的客户。

2.重写toString方法,返回类型的中文名称。

5、Constants类

定义三个常量:MAX_SERVICE_TIME、MIN_SERVICE_TIME和COMMON_CUSTOMER_INTERVAL_TIME

6、MainClass类

1.用for循环创建出4个普通窗口,再创建出1一个快速窗口和一个VIP窗口。

2.接着再创建三个定时器,分别定时去创建新的普通客户号码、新的快速客户号码和新的VIP客户号码。

代码演示:

1.NumberMachine.java文件演示

package com.itheima.interview.bank;
//创建一个号码机器,用于生成三种不同客户的相关号码
public classNumberMachine {
//创建三个不同类型的成员变量
//普通用户
private NumberManagercommonManager = newNumberManager();
//快速用户
private NumberManagerexpressManager = new NumberManager();
//vip用户
private NumberManagervipManager = new NumberManager();

//因此这里需要同时生成三个get方法
public NumberManagergetCommonManager() {
return commonManager;
}
public NumberManagergetExpressManager() {
return expressManager;
}
public NumberManagergetVipManager() {
return vipManager;
}

//由于几个对象访问的是同一个数据,而为了保证线程的安全性,这里需要将其设计成单例模式
//1.将构造函数私有化
private NumberMachine(){}
//2.创建本类对象
private static NumberMachine instance =new NumberMachine();
//3.创建一个公共的访问方式
public static NumberMachinegetInstance(){
return instance;
}

}


2.NumberManager.java文件演示:

package com.itheima.interview.bank;

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

//创建一个号码管理器对象NumberManager
public class NumberManager {
//创建一个上一次生成的号码
privateint lastNumber = 1;

//创建一个容器,用于存储号码生成器自动生成的号码
//为了方便于面向对象编程,这里直接定义成List,并且尽量使用超类
privateList<Integer> queueNumber = new ArrayList<Integer>();
//创建一个生成号码的方法,返回值为Integer包装类
publicsynchronized Integer generateNewManager(){
//将生成的号码存储进容器
queueNumber.add(lastNumber);
returnlastNumber++;
}

//创建一个在窗口取号的方法
publicsynchronized Integer fetchServiceNumber(){
Integernumber = null;
//由于取号的时候可能第一个号码还没出来就要被移除,因此这里需要进行判断
if(queueNumber.size()> 0)
number= queueNumber.remove(0);
//通过remove即可得到取出的号
returnnumber;
}
}


小结:1.由于generateNumberManager()和fetchServiceNumber()这两个不同的线程访问了相同的数据,那么就要将其添加同步技术

3.ServiceWindow.java文件演示

package com.itheima.interview.bank;

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

//创建一个服务窗口,用于给不同客户服务
public class ServiceWindow {
//定义一个变量,用于记录窗口的属性,默认属性为普通客户
privateCustomerType type = CustomerType.COMMON;

//创建一个窗口号
privateint windowId = 1;
//创建两者的构造方法
publicvoid setType(CustomerType type) {
this.type= type;
}
publicvoid setWindowId(int windowId) {
this.windowId= windowId;
}
//创建一个开启服务的方法
publicvoid start(){
//这里就需要定义一个线程池,用于执行一个独立线程
Executors.newSingleThreadExecutor().execute(newRunnable(){
publicvoid run(){
//取出号码
while(true){
switch(type){
caseCOMMON:
commonService();
break;
caseEXPRESS:
expressService();
break;
caseVIP:
vipService();
break;
}
}
}
});
}
//普通用户
privatevoid commonService() {
StringwindowName = "第" + windowId + "号" + type + "窗口";
Integernumber = NumberMachine.getInstance().getCommonManager().fetchServiceNumber();
System.out.println(windowName+ "正在获取任务");
if(number!= null){
System.out.println(windowName+ "为第" +number +"个" +"普通" +"客户服务");
//创建服务台为客户服务的时间
longbeginTime = System.currentTimeMillis();
//创建一个随机值,用于记录客户可能需要服务的随机值
intmaxRand = Constants.MAX_SERVICE_TIME - Constants.MIN_SERVICE_TIME;
//生成这个随机时间
longserverTime = new Random().nextInt(maxRand) + 1 + Constants.MIN_SERVICE_TIME;
//定义一个为客户服务的最短和最长的时间
try{
Thread.sleep(serverTime);
}catch (InterruptedException e) {
e.printStackTrace();
}
longcostTime = System.currentTimeMillis() - beginTime;
System.out.println(windowName+ "为第" +number + "个" +"普通"+"客户完成服务,耗时"+ costTime / 1000 + "秒" );
}else{
System.out.println(windowName+ "没有取到任务,先休息一会儿");
try{
Thread.sleep(1000);
}catch (InterruptedException e) {
e.printStackTrace();
}
}
}

//快速用户
privatevoid expressService() {
StringwindowName = "第" + windowId + "号" + type + "窗口";
Integernumber = NumberMachine.getInstance().getExpressManager().fetchServiceNumber();
System.out.println(windowName+ "正在获取任务");
if(number!= null){
System.out.println(windowName+ "为第" +number +"个" + type+ "客户服务");
//创建服务台为客户服务的时间
longbeginTime = System.currentTimeMillis();
try{//快速窗口休息的时间只能是最小值
Thread.sleep(Constants.MIN_SERVICE_TIME);
}catch (InterruptedException e) {
e.printStackTrace();
}
longcostTime = System.currentTimeMillis() - beginTime;
System.out.println(windowName+ "为第" +number + "个" + type+"客户完成服务,耗时"+ costTime / 1000 + "秒" );
}else{
System.out.println(windowName+ "没有取到任务");
commonService();
}
}

//vip用户
privatevoid vipService() {
StringwindowName = "第" + windowId + "号" + type + "窗口";
Integernumber = NumberMachine.getInstance().getVipManager().fetchServiceNumber();
System.out.println(windowName+ "正在获取任务");
if(number!= null){
System.out.println(windowName+ "为第" +number +"个" + type+ "客户服务");
//创建服务台为客户服务的时间
longbeginTime = System.currentTimeMillis();
//创建一个随机值,用于记录客户可能需要服务的随机值
intmaxRand = Constants.MAX_SERVICE_TIME - Constants.MIN_SERVICE_TIME;
//生成这个随机时间
longserveTime = new Random().nextInt(maxRand) + 1 + Constants.MIN_SERVICE_TIME;
//定义一个为客户服务的最短和最长的时间
longserverTime = 0;
try{
Thread.sleep(serverTime);
}catch (InterruptedException e) {
e.printStackTrace();
}
longcostTime = System.currentTimeMillis() - beginTime;
System.out.println(windowName+ "为第" +number + "个" + type+"客户完成服务,耗时"+ costTime / 1000 + "秒" );
}else{
System.out.println(windowName+ "没有取到任务");
commonService();
}
}
}


小结:

1.switch的执行效率比if else执行效率高;

2.switch中可传入的参数只能是byte、short、int、char和String等数据类型

3.可以将vip和快速窗口设计成普通窗口的子类,继而简化代码

需要抽取出来并设计成方法的有:

1.Integernumber = NumberMachine.getInstance().getVipManager().fetchServiceNumber();

2.System.out.println(windowName+ "没有取到任务,先休息一会儿");

4.由于fetchServiceNumber()函数中有一个阻塞式方法,因此需要将输出的语句放到其下面,方便于测试时观看

4.CustomerType.java文件演示

package com.itheima.interview.bank;
//创建一个枚举方法,用于记录各种客户属性
public enum CustomerType {
COMMON,EXPRESS,VIP;

//为了方便于观看,这里将复写toString方法
publicString toString(){
switch(this){
caseCOMMON:
return"普通";
caseEXPRESS:
return"快速";
caseVIP:
returnname();
}
//为了让程序顺利执行,需要在最后加一句return null;
returnnull;
}
}


5.Constants.java文件演示

package com.itheima.interview.bank;
//创建一个枚举方法,用于记录各种客户属性
public enum CustomerType {
COMMON,EXPRESS,VIP;

//为了方便于观看,这里将复写toString方法
publicString toString(){
switch(this){
caseCOMMON:
return"普通";
caseEXPRESS:
return"快速";
caseVIP:
returnname();
}
//为了让程序顺利执行,需要在最后加一句return null;
returnnull;
}
}


6.MainClass.java文件演示

package com.itheima.interview.bank;

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

public class MainClass {

publicstatic void main(String[] args) {
//创建几个普通窗口对象
for(inti=1; i<5; i++){
ServiceWindowcommonWindow = new ServiceWindow();
commonWindow.setWindowId(i);
commonWindow.start();
}

//创建快速窗口对象
ServiceWindowexpressWindow = new ServiceWindow();
expressWindow.setType(CustomerType.EXPRESS);
expressWindow.start();

//创建vip窗口对象
ServiceWindowvipWindow = new ServiceWindow();
vipWindow.setType(CustomerType.VIP);
vipWindow.start();

//模拟三类客户来银行获取服务,创建线程池
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
newRunnable(){
publicvoid run(){
//普通用户取号
Integernumber = NumberMachine.getInstance().getCommonManager().generateNewManager();
System.out.println(number+ "号普通用户等待服务!");
}
},
0,
Constants.COMMON_CUSTOMER_INTERVAL_TIME,
TimeUnit.SECONDS);

//快速用户
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
newRunnable(){
publicvoid run(){
//快速用户取号
Integernumber = NumberMachine.getInstance().getExpressManager().generateNewManager();
System.out.println(number+ "号快速用户等待服务!");
}
},
0,
Constants.COMMON_CUSTOMER_INTERVAL_TIME* 2,
TimeUnit.SECONDS);

//vip用户
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
newRunnable(){
publicvoid run(){
//vip用户取号
Integernumber = NumberMachine.getInstance().getVipManager().generateNewManager();
System.out.println(number+ "号vip用户等待服务!");
}
},
0,
Constants.COMMON_CUSTOMER_INTERVAL_TIME* 6,
TimeUnit.SECONDS);

}

}


----------------------
ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------

详细请查看:http://edu.csdn.net
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: