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

黑马程序员-7K月薪面试题破解之二_银行业务调度系统

2013-11-11 20:48 465 查看
----------------------
ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------



面向对象的分析与设计

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

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

NumberManager类

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

这里要注意的是多线程并发的安全问题

generateNewManager()和fetchServiceNumber()

都是在操作同一个数据lastNumber,一个在取,一个在添加,两者不能同时进行

所以必须给这两个方法加上锁标记synchronied

代码:

package com.isoftstone.interview.bank;

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

public class NumberManager {
private int lastNumber = 0;
//产生第一个号码
private List<Integer> queueNumber = new ArrayList<Integer>();
//创建一个集合,装排队的号码
public synchronized Integer generateNewManager()
{//产生号码
queueNumber.add(++lastNumber);
return lastNumber;
}

public synchronized Integer fetchServiceNumber()
{//取出一个号码
Integer number = null;
if(queueNumber.size()>0){
number = queueNumber.remove(0);
}
return number;
}
}


NumberMachine类

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

将NumberMachine类设计成单例

代码:

package com.isoftstone.interview.bank;

public class NumberMachine {
private NumberManager commonManager = new NumberManager();
private NumberManager expressManager = new NumberManager();
private NumberManager VIPManager = new NumberManager();

private void NumberMachine() {
// 把构造函数私有化,利用单例模式
}
public static NumberMachine getInstance() {
// 返回一个对象
return instance;
}

private static NumberMachine instance = new NumberMachine();
// 要定义为静态

public NumberManager getCommonManager() {
return commonManager;
}

public NumberManager getExpressManager() {
return expressManager;
}

public NumberManager getVIPManager() {
return VIPManager;
}

}


CustomerType枚举类

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

重写toString方法,返回类型的中文名称。这是在后面编码时重构出来的,刚开始不用考虑。

代码:

package com.isoftstone.interview.bank;

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


ServiceWindow类

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

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

代码:

package com.isoftstone.interview.bank;

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

public class ServiceWindow {
private CustomerType type = CustomerType.COMMON;
private int windowId = 1;

public void setType(CustomerType 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;
}
//NumberMachine.getInstance().getCommonManger();
}
}
});
}
private void commonService() {
String windowName = "第" + windowId +"号"+type+"窗口";
System.out.println(windowName+"正在叫号");
//得到号码机器,并取出普通号码管理器,并取出一个号码
Integer number = NumberMachine.getInstance().getCommonManager().fetchServiceNumber();
//如果返回的号码不为空
if(number!=null){
System.out.println(windowName + "开始为第" + number + "号普通客户服务");
//记录当前的系统时间
long beginTime = System.currentTimeMillis();
//确定处理业务的耗时范围
int maxRand = Constants.MAX_SERVICE_TIME-Constants.MIN_SERVICE_TIME;
//得到一个在范围内的一个实际随机耗时
long serviceTime = new Random().nextInt(maxRand)+1+Constants.MIN_SERVICE_TIME;
try {//让程序睡眠指定的时间,模拟业务耗时
Thread.sleep(serviceTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
//得到现在的系统时间,并减去之前的系统时间,得到模拟处理业务的耗时
long costTime = System.currentTimeMillis()-beginTime;
System.out.println(windowName + "为第" + number+"个"+type+"客户完成服务,耗时" +costTime/1000 + "秒");
}else{
System.out.println(windowName+"没有取到服务任务");
}
}

private void expressService() {
String windowName = "第" + windowId +"号"+type+"窗口";
System.out.println(windowName+"正在叫号");
//得到号码机器,并取出普通号码管理器,并取出一个号码
Integer number = NumberMachine.getInstance().getExpressManager().fetchServiceNumber();
//如果返回的号码不为空
if(number!=null){
//记录当前的系统时间
System.out.println(windowName + "开始为第" + number + "号快速客户服务");
long beginTime = System.currentTimeMillis();
//确定处理业务的耗时范围
int maxRand = Constants.MAX_SERVICE_TIME-Constants.MIN_SERVICE_TIME;
//得到一个在范围内的一个实际随机耗时
long serviceTime = new Random().nextInt(maxRand)+1+Constants.MIN_SERVICE_TIME;
try {//让程序睡眠指定的时间,模拟业务耗时
Thread.sleep(serviceTime);
} 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(Constants.MIN_SERVICE_TIME);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

private void vipService() {
String windowName = "第" + windowId +"号"+type+"窗口";
System.out.println(windowName+"正在叫号");
//得到号码机器,并取出普通号码管理器,并取出一个号码
Integer number = NumberMachine.getInstance().getVIPManager().fetchServiceNumber();
//如果返回的号码不为空
if(number!=null){
System.out.println(windowName + "开始为第" + number + "号VIP客户服务");
//记录当前的系统时间
long beginTime = System.currentTimeMillis();
//确定处理业务的耗时范围
int maxRand = Constants.MAX_SERVICE_TIME-Constants.MIN_SERVICE_TIME;
//得到一个在范围内的一个实际随机耗时
long serviceTime = new Random().nextInt(maxRand)+1+Constants.MIN_SERVICE_TIME;
try {//让程序睡眠指定的时间,模拟业务耗时
Thread.sleep(serviceTime);
} 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(Constants.MIN_SERVICE_TIME);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}


MainClass类

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

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

代码:

package com.isoftstone.interview.bank;

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

public class MainClass {
public static void main(String[] args) throws InterruptedException{
for(int i=0;i<5;i++){
ServiceWindow commonWindow = new ServiceWindow();
commonWindow.setWindowId(i);
commonWindow.start();
}

ServiceWindow expressWindow = new ServiceWindow();
expressWindow.setType(CustomerType.EXPRESS);
expressWindow.start();

ServiceWindow vipWindow = new ServiceWindow();
vipWindow.setType(CustomerType.VIP);
vipWindow.start();

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

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

Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
new Runnable(){
public void run(){
Integer number = NumberMachine.getInstance().getVIPManager().generateNewManager();
System.out.println(number+"号VIP客户在等待服务");
}
},
0,
Constants.COMMON_CUST_TIME*6,
TimeUnit.MILLISECONDS );
}
}


Constants类

定义三个常量:

MAX_SERVICE_TIME、MIN_SERVICE_TIME、COMMON_CUSTOMER_INTERVAL_TIME

代码:

package com.isoftstone.interview.bank;

public class Constants {
public static int MAX_SERVICE_TIME = 1000;
public static int MIN_SERVICE_TIME = 100;
public static int COMMON_CUST_TIME = 100;
}

总结:

银行业务调度这个项目,关键的点在于面向对象的分析,联系生活

(1) 首先确定存在哪几个对象

此项目中存在三个类1:产生号码的管理器 2:选择窗口的号码机器 3:窗口

(2) 确定类与类之间有什么关系

选择窗口的机器只有一台,使用单例模式创建对象,不同的窗口有各自对应的选择窗口的机器,所以要创建三个对象,选择窗口的机器对象操作产生号码的管理器,窗口调用号码管理器产生的号码

(3) 对象中的大概具有什么功能

产生号码的管理器类必须提供产生新号码以及删除号码的方法

选择窗口的号码机器能根据不同的用户调用不同号码产生器的方法

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

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