下面是张孝祥老师的经典例子,可以让我们更深入的理解,面向对象的分析和设计。
一个重要的经验就是谁拥有数据,谁就提供操作数据的方法。
1,两块石头磨成一把刀,石刀可以砍树,砍成木材,木材做成椅子。
stone 石头不能自己把自己变成石刀。
stoneknife 可以通过石刀加工场让石头变成石刀 =knifeFactory.creatKnife(stone,stone);
tree
material 石刀可以拥有砍的方法,通过这个方法把树变成木材。=stoneknife.cut(tree)
chair 椅子也需要一个加工场来吧木材变成椅子。=chairFactory.makeChair(material);
好了,看完了上面的例子,我们来跟着张老师来完成这个管理系统。
首先需求:
模拟实现银行业务调度系统逻辑,具体需求如下:
银行内有6个业务窗口,1 - 4号窗口为普通窗口,5号窗口为快速窗口,6号窗口为VIP窗口。
有三种对应类型的客户:VIP客户,普通客户,快速客户(办理如交水电费、电话费之类业务的客户)。
异步随机生成各种类型的客户,生成各类型用户的概率比例为:
VIP客户 :普通客户 :快速客户 = 1 :6 :3。
客户办理业务所需时间有最大值和最小值,在该范围内随机设定每个VIP客户以及普通客户办理业务所需的时间,快速客户办理业务所需时间为最小值(提示:办理业务的过程可通过线程Sleep的方式模拟)。
各类型客户在其对应窗口按顺序依次办理业务。
当VIP(6号)窗口和快速业务(5号)窗口没有客户等待办理业务的时候,这两个窗口可以处理普通客户的业务,而一旦有对应的客户等待办理业务的时候,则优先处理对应客户的业务。
随机生成客户时间间隔以及业务办理时间最大值和最小值自定,可以设置。
不要求实现GUI,只考虑系统逻辑实现,可通过Log方式展现程序运行结果。
根据分析,我们首先设计好自己的思路。
第一点,我们要有个数据管理系统,即NumberManager,
然后这个管理系统要被一个机器返回你具体要那个数据管理系统。NumberMachine
这时我们还需要客户的对象类,我们要根据这个类,来向机器所要具体的数据管理系统。
最后我们就需要一个服务窗口,ServerWindow
分析到这基本可以写了,要是写的过程发现少点什么可以在添加。但是大致方向已经定好了。
数据管理类:
import java.util.*;
public class NumberManager {
private int lastNumber=0;//设置一个数值,相当于来银行办理业务的客户。
private List<Integer> queueNumber=new ArrayList<Integer>();
public synchronized Integer gengerateNewManager(){//考虑到线程安全加同步锁,因为可能多客户同时进入等待区
queueNumber.add(++lastNumber);//将客户加入到等待区
return lastNumber;
}
public synchronized Integer fetchServiceNumber(){//考虑到线程安全加同步锁,因为可能多窗口同时呼叫客户
if(queueNumber.size()>0){
return (Integer)queueNumber.remove(0);//呼叫客户到窗口办理业务。
}else{
return null;
}
}
}
这个类看着还简单吧,就是一个存和取的过程。
public class NumberMachine {
//分别创建管理对象示例,每个管理对象示例负责不同的客户群。
private NumberManager commonManager=new NumberManager();
private NumberManager expressManager=new NumberManager();
private NumberManager vipManager=new NumberManager();
public NumberManager getCommonManager() {
return commonManager;
}
public NumberManager getExpressManager() {
return expressManager;
}
public NumberManager getVipManager() {
return vipManager;
}
private NumberMachine(){}//相同的客户群用的是同一个管理器,所以这设计成单例模式
public static NumberMachine getInstance(){
return instance;
}
private static NumberMachine instance=new NumberMachine();
}
这段代码也比较简单,很好懂就不多说了。
用枚举类列出3中客户类型:
public enum CustomerType {
COMMON,EXPRESS,VIP;
public String toString(){
switch(this){
case COMMON:
return "普通";
case EXPRESS:
return "快速";
case VIP:
return name();
}
return null;
}
}
好了,前奏完了,下面才是最重要的环节,ServerWindow服务窗口,其实这才是中枢系统。
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() {//创建线程池。
@Override
public void run() {
// TODO Auto-generated method stub
//通过客户类型判断启动哪个服务窗口
while (true) {
switch (type) {
case COMMON:
commonServer();
break;
case EXPRESS:
expressServer();
break;
case VIP:
vipServer();
break;
}
}
}
});
}
private void commonServer() {//普通客户服务区,
System.out.println("第" + windowId + "号" + type + "窗口" + "正在获取普通任务");
Integer number = NumberMachine.getInstance().getCommonManager()
.fetchServiceNumber();//从普通客户管理器中获取客户号
if (number != null) {//如果不是null,则为其服务
long beginTime = System.currentTimeMillis();//纪录开始时间
try {
Thread.sleep((new Random()//采用随机数来模拟服务时间。
.nextInt(Constancs.MAX_SERVICE_TIME + 1))//这是一个常量,放在常量类里面。
+ Constancs.MIN_SERVICE_TIME);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
long endTime = (System.currentTimeMillis() - beginTime)/1000;//纪录结束时间
System.out.println("第" + windowId + "号" + type + "窗口" + "为第" + number + "个" + "普通"
+ "客户服务,用时" + (int)endTime + "秒");//输出服务信息
} else {//如果没有客户,就休息一秒在重新查看管理器
System.out.println("没有取到任务,休息1秒");
try {
Thread.sleep(Constancs.MIN_SERVICE_TIME);//这是一个常量,放在常量类里面。
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
private void expressServer() {//快速服务区,下面基本和上面一样,只把不一样的地方标示下。
System.out.println("第" + windowId + "号 快速窗口" + "正在获快速取任务");
Integer number = NumberMachine.getInstance().getExpressManager()
.fetchServiceNumber();
if (number != null) {
long beginTime = System.currentTimeMillis();
try {
Thread.sleep(Constancs.MIN_SERVICE_TIME);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
long endTime = (System.currentTimeMillis() - beginTime)/1000;
System.out.println("第" + windowId + "号" + type + "窗口" + "为第" + number + "个" + type
+ "客户服务,用时" +(int) endTime + "秒");
} else {//如果没有快速客户,则帮普通客户办理业务。普通客户没有在休息。
commonServer();
}
}
private void vipServer() {//VIP客户区,下面基本同上面
//String windowName = "第" + windowId + "号" + type + "窗口";
System.out.println("第" + windowId + "号VIP窗口" + "正在获取VIP任务");
Integer number = NumberMachine.getInstance().getVipManager()
.fetchServiceNumber();
if (number != null) {
long beginTime = System.currentTimeMillis();
try {
Thread.sleep((new Random()
.nextInt(Constancs.MAX_SERVICE_TIME + 1))
+ Constancs.MIN_SERVICE_TIME);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
long endTime = (System.currentTimeMillis() - beginTime)/1000;
System.out.println("第" + windowId + "号" + type + "窗口" + "为第" + number + "个" + type
+ "客户服务,用时" + (int)endTime + "秒");
} else {//如果没有VIP客户,则办理普通业务,没有在休息。
commonServer();
}
}
}
到这里就差不多完成了多一半了,下面补充一个常量类,是为了以后修改代码方便而提取出来的。
public class Constancs {
public static int MAX_SERVICE_TIME=10000;//模仿服务时间的最大值
public static int MIN_SERVICE_TIME=1000;//模仿服务时间的最小值
}
哈哈,还少一个主程序就完成了,暗爽一下吧。
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class MainBank {
public static void main(String[] args) {
for(int i=1;i<5;i++){//采用循环的模式启动4个普通窗口
ServiceWindow commomWindow=new ServiceWindow();
commomWindow.setWindowId(i);
commomWindow.start();
}
ServiceWindow expressWindow=new ServiceWindow();
expressWindow.setWindowId(5);//启动5号快速窗口
expressWindow.setType(CustomerType.EXPRESS);
expressWindow.start();
ServiceWindow vipWindow=new ServiceWindow();
vipWindow.setWindowId(6);//启动6号VIP窗口
vipWindow.setType(CustomerType.VIP);
vipWindow.start();
//创建3个定时器,模拟3种客户进入到等候区。
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
new Runnable() {
@Override
public void run() {
Integer number=NumberMachine.getInstance().getCommonManager().gengerateNewManager();
}
},
0,
1,//普通客户每一秒钟来一个
TimeUnit.SECONDS);
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
new Runnable() {
@Override
public void run() {
Integer number=NumberMachine.getInstance().getExpressManager().gengerateNewManager();
}
},
0,
2,//快速客户每两秒一个
TimeUnit.SECONDS);
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
new Runnable() {
@Override
public void run() {
Integer number=NumberMachine.getInstance().getVipManager().gengerateNewManager();
}
},
0,
6,//VIP客户每6秒一个。
TimeUnit.SECONDS);
}
}
------------- java培训、android培训、期待与您交流! -------------