黑马程序员_学习笔记_面试题_银行业务调度系统

来源:互联网 发布:学校 电子地图 软件 编辑:程序博客网 时间:2024/05/18 20:07

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


项目需求

请看项目需求图:

 

面向对象的设计与分析

对象分析:

通过上一个交通灯管理系统,对于面向对象有了一定的了解。而这个项目要怎样确定面向对象的编程思想呢?

看起来,对于用户来讲,有三种类型:VIP客户,普通客户,快速客户。通过异步随机生成各种类型的客户,各类型客户在其对应窗口按顺序依次办理业务。其实实际去银行办业务的时候,并不是每个用户参与银行业务的调度。而是每一个客户通过一个取号机器按顺序排队办理业务,因此,用户可以由取号机器产生号码的方式来表示。即建立一个号码管理器对象,让这个对象不断地产生号码,就等于随机生成了客户。而三类用户,需要通过三个号码管理器来管理,这三个对象又同一由一个号码产生机器进行管理。而这个号码机器在整个系统中始终只能有一个,所以,它要被设计成单例。

各类型客户在其对应窗口按顺序依次办理业务,准确地说,应该是窗口依次叫号。而各个窗口调用相应的号码管理器对象,获取所要叫的号码。即服务窗口每次找号码管理器获取当前要被服务的号码。

这样,将需要建立的对象整合在一起,就可以实现一个银行调度系统的要求了。

 

各类关系图:

 

程序编写

NumberManager类

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

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

详细代码如下:

 

package com.itheima;import java.util.*;public class NumberManager {private int lastNumber=1;//把客户要取的号码存在集合中private List<Integer> queneNumber = new ArrayList<Integer>();//客户取号线程,因为和下面的窗口叫号线程访问了相同的数据,为防止危险,需要加锁定public synchronized Integer generateNewManager(){queneNumber.add(lastNumber);return lastNumber++;}//窗口叫号的方法,需要加锁定public synchronized Integer fetchServiceNumber(){Integer number = null;if(queneNumber.size()>0)number = queneNumber.remove(0);return number;}}

NumberMachine类

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

2)将NumberMachine类设计成单例。

代码如下所示:

 

package com.itheima;public class NumberMachine {//创建三个不同客户的号码管理器private NumberManager commonManager = new NumberManager();private NumberManager expressManager = new NumberManager();private NumberManager VIPManager = new NumberManager();//用eclipse自动生成三个变量的get方法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();}

Customer枚举类

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

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

代码如下:

 

package com.itheima;//枚举类型public enum Customer {//创建三个类型的枚举对象COMMON,EXPRESS,VIP;//覆盖toString方法,返回对象的中文名称。public String toString(){switch(this){case COMMON:return "普通";case EXPRESS:return "快速";case VIP:return "VIP";}return null;}}

ServiceWindow类

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

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

代码如下所示

 

package com.itheima;import java.util.Random;import java.util.concurrent.Executors;public class ServiceWindow {//客户默认类型为普通private Customer type = Customer.COMMON;private int windowID = 1;public void setType(Customer 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){//switch比if else效率高。case COMMON:commonService();//调用普通客户服务的方法。break;case EXPRESS:expressService();//调用快速客户服务的方法。break;case VIP:VIPService();//调用VIP客户服务的方法。break;}}}});}private void commonService() {String windowName = "第"+windowID+"号"+type+"窗口";Integer number = NumberMachine.getInstance().getCommonManager().fetchServiceNumber();System.out.println(windowName+"正在获取服务任务");if(number != null){System.out.println(windowName+"正在为第"+number+"个普通进行服务");long beginTime = System.currentTimeMillis();int maxRand = Constants.MAX_SERVICE_TIME-Constants.MIN_SERVICE_TIME;long serveTime = new Random().nextInt(maxRand)+1+Constants.MIN_SERVICE_TIME;try {Thread.sleep(serveTime);} catch (InterruptedException e) {e.printStackTrace();}long endTime = System.currentTimeMillis();System.out.println(windowName+"为第"+number+"个普通客户完成服务,"+ "耗时"+(endTime-beginTime)/1000+"秒");}else{System.out.println(windowName+"没有获取到服务任务,空闲1秒钟");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}private void expressService() {String windowName = "第"+windowID+"号"+type+"窗口";Integer number = NumberMachine.getInstance().getExpressManager().fetchServiceNumber();System.out.println(windowName+"正在获取服务任务");if(number != null){System.out.println(windowName+"正在为第"+number+"个"+type+"进行服务");long beginTime = System.currentTimeMillis();//快速客户办理业务速度快,因此不需要下面两个时间方法。//int maxRand = Constants.MAX_SERVICE_TIME-Constants.MIN_SERVICE_TIME;//long serveTime = new Random().nextInt(maxRand)+1+Constants.MIN_SERVICE_TIME;try {Thread.sleep(Constants.MIN_SERVICE_TIME);} catch (InterruptedException e) {e.printStackTrace();}long endTime = System.currentTimeMillis();System.out.println(windowName+"为第"+number+"个"+type+"客户完成服务,"+ "耗时"+(endTime-beginTime)/1000+"秒");}else{System.out.println(windowName+"没有获取到服务任务!");commonService();}}private void VIPService() {String windowName = "第"+windowID+"号"+type+"窗口";Integer number = NumberMachine.getInstance().getVIPManager().fetchServiceNumber();System.out.println(windowName+"正在获取服务任务");if(number != null){System.out.println(windowName+"正在为第"+number+"个"+type+"进行服务");long beginTime = System.currentTimeMillis();int maxRand = Constants.MAX_SERVICE_TIME-Constants.MIN_SERVICE_TIME;long serveTime = new Random().nextInt(maxRand)+1+Constants.MIN_SERVICE_TIME;try {Thread.sleep(serveTime);} catch (InterruptedException e) {e.printStackTrace();}long endTime = System.currentTimeMillis();System.out.println(windowName+"完成对第"+number+"个"+type+"客户的服务,"+ "耗时"+(endTime-beginTime)/1000+"秒");}else{System.out.println(windowName+"没有获取到服务任务!");commonService();}}}

MainClass类

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

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

请看下面的代码:

 

package com.itheima;import java.util.concurrent.Executors;import java.util.concurrent.TimeUnit;public class MainClass {public static void main(String[] args) {//这里用for循环的方式,产生了四个普通窗口for(int i = 1;i<5;i++){ServiceWindow commonWindow= new ServiceWindow();commonWindow.setWindowID(i);commonWindow.start();}//产生一个快速窗口ServiceWindow expressWindow= new ServiceWindow();expressWindow.setType(Customer.EXPRESS);expressWindow.start();//产生一个VIP窗口ServiceWindow VIPWindow= new ServiceWindow();VIPWindow.setType(Customer.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_CUSTOMER_INTERVAL_TIME, //每一秒钟产生一个普通用户TimeUnit.SECONDS);//VIP客户取号Executors.newScheduledThreadPool(1).scheduleAtFixedRate(new Runnable(){public void run() {Integer number = NumberMachine.getInstance().getVIPManager().generateNewManager();System.out.println("注意!有客户来了!第"+number+"号VIP客户正在等待服务");}}, 0, Constants.COMMON_CUSTOMER_INTERVAL_TIME*6, //每6秒产生一个VIP客户。TimeUnit.SECONDS);//快速客户取号。Executors.newScheduledThreadPool(1).scheduleAtFixedRate(new Runnable(){public void run() {Integer number = NumberMachine.getInstance().getExpressManager().generateNewManager();System.out.println("来用户了!!第"+number+"号快速客户正在等待服务");}}, 0, Constants.COMMON_CUSTOMER_INTERVAL_TIME*2, //每2秒产生一个快速客户。TimeUnit.SECONDS);}}

Constants类

定义三个常量:

MAX_SERVICE_TIME、MIN_SERVICE_TIME、COMMON_CUSTOMER_INTERVAL_TIME

代码如下:

 

package com.itheima;public class Constants {public static int MAX_SERVICE_TIME = 10000;public static int MIN_SERVICE_TIME = 1000;//每一秒产生一个普通用户,这样2秒一个快速用户,6秒一个VIP用户比较合理public static int COMMON_CUSTOMER_INTERVAL_TIME = 1;}

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

详细请查看:http://edu.csdn.net


原创粉丝点击