黑马程序员--7k之银行业务调度系统
2014-07-20 00:11
260 查看
---------------------- ASP.Net+Android+IOS开发、.Net培训、期待与您交流!
----------------------
银行业务调度系统
需求:
模拟实现银行业务调度系统逻辑,具体需求如下:
Ø 银行内有6个业务窗口,1- 4号窗口为普通窗口,5号窗口为快速窗口,6号窗口为VIP窗口。
Ø 有三种对应类型的客户:VIP客户,普通客户,快速客户(办理如交水电费、电话费之类业务的客户)。
Ø 异步随机生成各种类型的客户,生成各类型用户的概率比例为:
VIP客户 :普通客户 :快速客户 = 1 :6 :3。
Ø 客户办理业务所需时间有最大值和最小值,在该范围内随机设定每个VIP客户以及普通客户办理业务所需的时间,快速客户办理业务所需时间为最小值(提示:办理业务的过程可通过线程Sleep的方式模拟)。
Ø 各类型客户在其对应窗口按顺序依次办理业务。
Ø 当VIP(6号)窗口和快速业务(5号)窗口没有客户等待办理业务的时候,这两个窗口可以处理普通客户的业务,而一旦有对应的客户等待办理业务的时候,则优先处理对应客户的业务。
Ø 随机生成客户时间间隔以及业务办理时间最大值和最小值自定,可以设置。
Ø 不要求实现GUI,只考虑系统逻辑实现,可通过Log方式展现程序运行结果。
需求分析:
生成的排队号码有三类:普通用户,快速用户,VIP用户。
三种号码是分开的,也就是号码生成器能生成三类独立的号码,三类号码的序号分别递增,互不影响。由此可以设计一个号码生成类NumberManager,用于生成号码,由于三种号码的生成逻辑一样,所以只用设计一个类即可。考虑到要生成三种类型的号码,所以可以创建三个NumberManager对象。
在NumberManager类中,有号码,就要有操作号码的方法:生成号码,为业务窗口提供号码。
一开始写的时候是这样写的,感觉很对,但是这样的话是肯定会出问题的。
原因就在于这个类里面提供的两个操作号码的方法是多线程操作的,生成号码一个线程,窗口取号码是一个线程,这两个线程所使用的号码是同一份。所以必须使用同步,不然就会出现安全问题。
这样就保证了共享数据的安全性。
在上面的fetchNumber方法中还要注意一点:业务窗口每取到一次号码,就要在号码集合中移除一个,每次取得都是最前面的号码,就是集合中的第0个号码,集合的remove方法不仅删除数据,并且会返回删除的数据,利用这一点,窗口取号和号码生成器中的号码集合删除号码的动作就合二为一,这是个小技巧。既方便编程,又保证数据安全。
NumberMachine类:号码生成机器
只有一个产生号码的机器,所以要用单例。
单例设计方法:把构造方法设置为private,有一个静态方法返回自身对象。
由于构造方法私有,所以在类之外不能创建该类对象,但在类之内可以创建对象。在类之内创建一个私有的类对象,写一个静态方法,静态方法返回创建的这个对象。这个对象是全局的,而且只有一个。这就是单例设计方法。
private NumberMachine(){} //构造方法,私有
private static NumberMachine instance = new NumberMachine();
public static NumberMachine getInstance()
{
return instance; //返回对象,所以可以通过getInstance()方法生成一个对象
}
再来分析业务窗口,业务窗口会有一个向号码生成器索要当前排队号码的活动,并且在银行上班期间,这个活动一直持续不会停,所以要单独给要号这个动作创建一个线程,让这个线程一直运行。
public void start(){
Executors.newSingleThreadExecutor().execute(
new Runnable(){ //这种匿名内部类表示创建一个内部类,该类实现Runnable接口。
public void run(){
while(true){
switch(type){
case COMMON:
commonService();
break;
case EXPRESS:
expressService();
break;
case VIP:
vipService();
break;
}
}
}
}
);
}
创建线程用到java5中的新的API:Executors。
该类创建一个线程池,当要执行某一任务时,把任务交给线程池,线程池内有很多线程,从内部找一个线程来执行该任务,这样做的好处就是可以提高效率。
一共有三种类型的客户,而且唯一确定:普通客户,快速客户,VIP客户。
所以想到用枚举,创建一个枚举客户类,类中有三个实例:
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 = name();
break;
}
return name;
}
}
覆盖了toString()方法的原因是希望返回中文。枚举类有一个name()方法,返回枚举实例的名字。
再回来分析业务窗口,实现业务:
new Runnable(){
public void run(){
while(true){
switch(type){
case COMMON:
commonService();
break;
case EXPRESS:
expressService();
break;
case VIP:
vipService();
break;
}
}
}
}
普通窗口向号码生成器取号
如果取到的号不为空,表明当前有人排队,则模拟为客户服务,让线程睡1-10秒。
快速窗口向号码生成器取号
如果取到的号不为空,表明当前有人排队,则模拟为客户服务,让线程睡1秒。
如果取不到号码,表明当前没有快速客户排队,则为普通客户服务,向普通用户号码生成器取号。
VIP窗口的业务逻辑和快速窗口的业务逻辑一样。
在MainClass中,先启动服务窗口的线程开始向号码生成器取号
//产生4个普通窗口
for(int i=1;i<5;i++){
ServiceWindow window = new ServiceWindow();
window.setNumber(i);
window.start();
}
//产生1个快速窗口
ServiceWindow expressWindow = new ServiceWindow();
expressWindow.setType(CustomerType.EXPRESS);
expressWindow.start();
//产生1个VIP窗口
ServiceWindow vipWindow = new ServiceWindow();
vipWindow.setType(CustomerType.VIP);
vipWindow.start();
然后开始出现客户:
有三种客户,比例为:
VIP客户 :普通客户 :快速客户 = 1 :6 :3。
所以创建并启动三个线程,分别产生普通号,快速号,VIP号。
Executors.newScheduledThreadPool(1).scheduleAtFixedRate();
Executors.newScheduledThreadPool(1).scheduleAtFixedRate();
Executors.newScheduledThreadPool(1).scheduleAtFixedRate();
这种线程是带定时器的线程。
线程的执行代码中向客户集合中增加客户,由于三类客户的比例为1:6:3,也就是同样的时间,来的普通客户是快速客户的2倍,是VIP客户的6倍。
也就是说,如果m秒来一个普通客户,则2m秒才来一个快速客户,6m秒来一个VIP客户。
所以在三个计数器线程里面,三个时间间隔的比值为1:2:6。
其实这种java1.5的线程API的效果,用原来的API也可以实现,无非就是用一个while(true)语句,实现循环。在线程里面,通过让线程睡眠的方法设置时间间隔。
虽然在编程时都能达到效果,但是只好是用新的技术,因为新的技术是对原来旧的技术的改良,改良的效果是提高了效率。
在这个项目中,用到的知识点有:集合,单例,枚举,线程。
我觉得之所以有难度,是因为现在还没有形成面向对象程序设计的思想,在听张孝祥老师的课时,张老师说过,面向对象的设计思想是通过不断地积累经验而形成的,刚开始要去模仿别人的编程风格,久而久之自然形成这种习惯,也能在看到需求时,很快的分析出来面向对象设计的流程。
面向对象程序设计的一个规则:谁拥有数据,对数据进行操作的方法就由谁提供。
通过这个项目的学习,理解面向对象程序设计的思想,积累面向对象程序设计的经验。
----------------------
银行业务调度系统
需求:
模拟实现银行业务调度系统逻辑,具体需求如下:
Ø 银行内有6个业务窗口,1- 4号窗口为普通窗口,5号窗口为快速窗口,6号窗口为VIP窗口。
Ø 有三种对应类型的客户:VIP客户,普通客户,快速客户(办理如交水电费、电话费之类业务的客户)。
Ø 异步随机生成各种类型的客户,生成各类型用户的概率比例为:
VIP客户 :普通客户 :快速客户 = 1 :6 :3。
Ø 客户办理业务所需时间有最大值和最小值,在该范围内随机设定每个VIP客户以及普通客户办理业务所需的时间,快速客户办理业务所需时间为最小值(提示:办理业务的过程可通过线程Sleep的方式模拟)。
Ø 各类型客户在其对应窗口按顺序依次办理业务。
Ø 当VIP(6号)窗口和快速业务(5号)窗口没有客户等待办理业务的时候,这两个窗口可以处理普通客户的业务,而一旦有对应的客户等待办理业务的时候,则优先处理对应客户的业务。
Ø 随机生成客户时间间隔以及业务办理时间最大值和最小值自定,可以设置。
Ø 不要求实现GUI,只考虑系统逻辑实现,可通过Log方式展现程序运行结果。
需求分析:
生成的排队号码有三类:普通用户,快速用户,VIP用户。
三种号码是分开的,也就是号码生成器能生成三类独立的号码,三类号码的序号分别递增,互不影响。由此可以设计一个号码生成类NumberManager,用于生成号码,由于三种号码的生成逻辑一样,所以只用设计一个类即可。考虑到要生成三种类型的号码,所以可以创建三个NumberManager对象。
在NumberManager类中,有号码,就要有操作号码的方法:生成号码,为业务窗口提供号码。
一开始写的时候是这样写的,感觉很对,但是这样的话是肯定会出问题的。
原因就在于这个类里面提供的两个操作号码的方法是多线程操作的,生成号码一个线程,窗口取号码是一个线程,这两个线程所使用的号码是同一份。所以必须使用同步,不然就会出现安全问题。
这样就保证了共享数据的安全性。
在上面的fetchNumber方法中还要注意一点:业务窗口每取到一次号码,就要在号码集合中移除一个,每次取得都是最前面的号码,就是集合中的第0个号码,集合的remove方法不仅删除数据,并且会返回删除的数据,利用这一点,窗口取号和号码生成器中的号码集合删除号码的动作就合二为一,这是个小技巧。既方便编程,又保证数据安全。
NumberMachine类:号码生成机器
只有一个产生号码的机器,所以要用单例。
单例设计方法:把构造方法设置为private,有一个静态方法返回自身对象。
由于构造方法私有,所以在类之外不能创建该类对象,但在类之内可以创建对象。在类之内创建一个私有的类对象,写一个静态方法,静态方法返回创建的这个对象。这个对象是全局的,而且只有一个。这就是单例设计方法。
private NumberMachine(){} //构造方法,私有
private static NumberMachine instance = new NumberMachine();
public static NumberMachine getInstance()
{
return instance; //返回对象,所以可以通过getInstance()方法生成一个对象
}
再来分析业务窗口,业务窗口会有一个向号码生成器索要当前排队号码的活动,并且在银行上班期间,这个活动一直持续不会停,所以要单独给要号这个动作创建一个线程,让这个线程一直运行。
public void start(){
Executors.newSingleThreadExecutor().execute(
new Runnable(){ //这种匿名内部类表示创建一个内部类,该类实现Runnable接口。
public void run(){
while(true){
switch(type){
case COMMON:
commonService();
break;
case EXPRESS:
expressService();
break;
case VIP:
vipService();
break;
}
}
}
}
);
}
创建线程用到java5中的新的API:Executors。
该类创建一个线程池,当要执行某一任务时,把任务交给线程池,线程池内有很多线程,从内部找一个线程来执行该任务,这样做的好处就是可以提高效率。
一共有三种类型的客户,而且唯一确定:普通客户,快速客户,VIP客户。
所以想到用枚举,创建一个枚举客户类,类中有三个实例:
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 = name();
break;
}
return name;
}
}
覆盖了toString()方法的原因是希望返回中文。枚举类有一个name()方法,返回枚举实例的名字。
再回来分析业务窗口,实现业务:
new Runnable(){
public void run(){
while(true){
switch(type){
case COMMON:
commonService();
break;
case EXPRESS:
expressService();
break;
case VIP:
vipService();
break;
}
}
}
}
普通窗口向号码生成器取号
如果取到的号不为空,表明当前有人排队,则模拟为客户服务,让线程睡1-10秒。
快速窗口向号码生成器取号
如果取到的号不为空,表明当前有人排队,则模拟为客户服务,让线程睡1秒。
如果取不到号码,表明当前没有快速客户排队,则为普通客户服务,向普通用户号码生成器取号。
VIP窗口的业务逻辑和快速窗口的业务逻辑一样。
在MainClass中,先启动服务窗口的线程开始向号码生成器取号
//产生4个普通窗口
for(int i=1;i<5;i++){
ServiceWindow window = new ServiceWindow();
window.setNumber(i);
window.start();
}
//产生1个快速窗口
ServiceWindow expressWindow = new ServiceWindow();
expressWindow.setType(CustomerType.EXPRESS);
expressWindow.start();
//产生1个VIP窗口
ServiceWindow vipWindow = new ServiceWindow();
vipWindow.setType(CustomerType.VIP);
vipWindow.start();
然后开始出现客户:
有三种客户,比例为:
VIP客户 :普通客户 :快速客户 = 1 :6 :3。
所以创建并启动三个线程,分别产生普通号,快速号,VIP号。
Executors.newScheduledThreadPool(1).scheduleAtFixedRate();
Executors.newScheduledThreadPool(1).scheduleAtFixedRate();
Executors.newScheduledThreadPool(1).scheduleAtFixedRate();
这种线程是带定时器的线程。
线程的执行代码中向客户集合中增加客户,由于三类客户的比例为1:6:3,也就是同样的时间,来的普通客户是快速客户的2倍,是VIP客户的6倍。
也就是说,如果m秒来一个普通客户,则2m秒才来一个快速客户,6m秒来一个VIP客户。
所以在三个计数器线程里面,三个时间间隔的比值为1:2:6。
其实这种java1.5的线程API的效果,用原来的API也可以实现,无非就是用一个while(true)语句,实现循环。在线程里面,通过让线程睡眠的方法设置时间间隔。
虽然在编程时都能达到效果,但是只好是用新的技术,因为新的技术是对原来旧的技术的改良,改良的效果是提高了效率。
在这个项目中,用到的知识点有:集合,单例,枚举,线程。
我觉得之所以有难度,是因为现在还没有形成面向对象程序设计的思想,在听张孝祥老师的课时,张老师说过,面向对象的设计思想是通过不断地积累经验而形成的,刚开始要去模仿别人的编程风格,久而久之自然形成这种习惯,也能在看到需求时,很快的分析出来面向对象设计的流程。
面向对象程序设计的一个规则:谁拥有数据,对数据进行操作的方法就由谁提供。
通过这个项目的学习,理解面向对象程序设计的思想,积累面向对象程序设计的经验。
相关文章推荐
- 黑马程序员-7K面试题破解(银行业务调度系统)
- 黑马程序员-7K月薪面试题破解之二_银行业务调度系统
- 黑马程序员_7K月薪面试题破解之二_银行业务调度系统
- 黑马程序员-7k面试题 银行业务调度系统
- 黑马程序员_7k面试题之银行业务调度系统
- 黑马程序员——7K面试题之银行业务调度系统
- 黑马程序员 7K月薪面试题破解之二 -- 银行业务调度系统
- 黑马程序员 7k面试题破解: 银行业务调度系统
- 黑马程序员_张孝祥_7K月薪面试题_银行业务调度系统
- 黑马程序员---7k面试题(银行业务调度系统)
- 【黑马程序员】银行业务调度系统
- 黑马程序员_7K面试题之银行业务调度系统
- 黑马程序员_张孝祥7K面试题——银行调度系统学习随感
- 黑马程序员---银行业务调度系统
- 黑马程序员—7k月薪面试题之银行业务调度系统
- 黑马程序员---银行业务调度系统
- 黑马程序员_银行业务调度系统
- 黑马程序员_7K面试_银行业务高度系统_31
- 黑马程序员--银行业务调度系统--java学习日记14(7K)
- 黑马程序员_银行业务调度系统