黑马程序员:银行业务调度系统分析及代码实现
2013-11-21 12:45
381 查看
----------------------
ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------银行业务调度系统
对象分析:
1.客户
2.服务窗口
3.号码机器
对象上的属性和方法分析:
客户
客户类型:普通客户、快速客户、VIP客户
需要用到枚举:因为客户类型是固定的三类客户
服务窗口
窗口类型:普通窗口、快速窗口、VIP窗口
功能:
1.提供设置窗口号、窗口类型的方法
2.获取号码并处理客户业务
需要用到多线程:因为是多个窗口同时工作的
号码机器
号码:普通号码、快速号码、VIP号码
功能:产生号码提供给客户、将产生的最前面的号码提供给窗口
需要用到同步:因为两个方法是不同线程操作,当多个线程操作同一个数据的时候会出现问题,所以要让他们互斥。
需要用到单例:因为号码机器只有一台
CustomerType:客户类型
ServiceWindows:服务窗口
NumberManager:号码管理器
NumberMechine:号码机器
Constants:常量
mainClass:模拟运行系统
----------------------
ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------详细请查看:http://edu.csdn.net
ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------银行业务调度系统
对象分析:
1.客户
2.服务窗口
3.号码机器
对象上的属性和方法分析:
客户
客户类型:普通客户、快速客户、VIP客户
需要用到枚举:因为客户类型是固定的三类客户
服务窗口
窗口类型:普通窗口、快速窗口、VIP窗口
功能:
1.提供设置窗口号、窗口类型的方法
2.获取号码并处理客户业务
需要用到多线程:因为是多个窗口同时工作的
号码机器
号码:普通号码、快速号码、VIP号码
功能:产生号码提供给客户、将产生的最前面的号码提供给窗口
需要用到同步:因为两个方法是不同线程操作,当多个线程操作同一个数据的时候会出现问题,所以要让他们互斥。
需要用到单例:因为号码机器只有一台
CustomerType:客户类型
/* * 因为客户类型是固定的三种类型,所以使用枚举 * 判断当前枚举类型,并覆盖toString方法,根据枚举类型指定对应的客户类型name */ package cn.itcast.Mr_Zhang.BankQueue; public enum CustomerType { COMMON,EXPRESS,VIP; public String toString(){ String name = null; switch(this){ case COMMON : name = "普通客户"; return name; case EXPRESS : name = "快速客户"; return name; case VIP : name = "VIP客户"; return name; } return null; } }
ServiceWindows:服务窗口
/* * 服务窗口共有三类:普通,快速,VIP * 1.若快速、VIP窗口没有未用户办理业务的时候,需要为普通客户办理业务 * 2.VIP客户:普通客户:快速客户 = 1:6:3 * 思路: * 1.窗口应该有对应的窗口ID、窗口名称、窗口类型 * 2.根据客户类型选择对应窗口的业务执行方法 * 3.窗口需要有工作的方法:即取号,并以Sleep代替办理业务的时间 * 4.当快速和VIP窗口没有对应的快速和VIP客户时,需调用普通窗口的方法为普通客户服务 */ package cn.itcast.Mr_Zhang.BankQueue; import java.util.Random; import java.util.concurrent.Executors; public class ServiceWindows { /*初始化窗口号及客户类型并提供外部设置的方法*/ private int windowId = 1; private CustomerType type = CustomerType.COMMON; public void setWindowId(int windowId) { this.windowId = windowId; } public void setType(CustomerType type) { this.type = type; } /*定义窗口启动方法,根据不同客户类型启动不同窗口 *这里要注意:若start中没用定义新线程来执行方法,那么在main方法中创建多个窗口的时候,第一个窗口被启动时就会一直循环。 *这里是完成整个项目犯错的地方,特别要注意 */ public void start(){ Executors.newSingleThreadExecutor().execute(new Runnable(){ public void run(){ switch(type){ case COMMON : /*因为窗口启动之后需要一直处理该类型的客户,所以要一直使用该窗口的方法*/ while(true) commonWindow(); case EXPRESS : while(true) expressWindow(); case VIP : while(true) vipWindow(); } } }); } /*普通窗口*/ private void commonWindow() { String windowName = "第" + windowId + "号" + type + "窗口"; Integer number = NumberMechine.getNumberMechine().getCommonNumber().fetchNumber(); System.out.println(windowName + "正在获取任务"); if (number != null) try { int maxRondom = Constants.SERVICE_TIME_MAX - Constants.SERVICE_TIME_MIN; int serviceTime = new Random().nextInt(maxRondom) + 1 + Constants.SERVICE_TIME_MIN; Thread.sleep(serviceTime); System.out.println(windowName + "为第" + number + "号" + "普通客户服务,耗时:" + serviceTime/1000 + "秒"); } catch (InterruptedException e) { e.printStackTrace(); } else System.out.println(windowName + "没有获取到任务,等待一秒钟"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } /*快速窗口*/ private void expressWindow() { String windowName = "第" + windowId + "号" + type + "窗口"; Integer number = NumberMechine.getNumberMechine().getExpressNumber().fetchNumber(); if (number != null) try { int serviceTime = Constants.SERVICE_TIME_MIN; Thread.sleep(serviceTime); System.out.println(windowName + "为第" + number + "号" + "快速客户服务,耗时:" + serviceTime/1000 + "秒"); } catch (InterruptedException e) { e.printStackTrace(); } else System.out.println(windowName + "未获取到任务,进入普通任务获取阶段"); commonWindow(); } /*VIP窗口*/ private void vipWindow() { String windowName = "第" + windowId + "号" + type + "窗口"; Integer number = NumberMechine.getNumberMechine().getVipNumber().fetchNumber(); if (number != null) try { int maxRondom = Constants.SERVICE_TIME_MAX - Constants.SERVICE_TIME_MIN; int serviceTime = new Random().nextInt(maxRondom) + 1 + Constants.SERVICE_TIME_MIN; Thread.sleep(serviceTime); System.out.println(windowName + "为第" + number + "号" + "VIP客户服务,耗时:" + serviceTime/1000 + "秒"); } catch (InterruptedException e) { e.printStackTrace(); } else System.out.println(windowName + "未获取到任务,进入普通任务获取阶段"); /*若VIP窗口未取得VIP号码管理中的号码,则为普通客户服务*/ commonWindow(); } }
NumberManager:号码管理器
/* * 号码管理器的功能: * 用户取号:产生号码 * 窗口取号:取得已产生号码的最前面的号码 */ package cn.itcast.Mr_Zhang.BankQueue; import java.util.ArrayList; import java.util.List; public class NumberManager { private Integer lastNumber = 1; private List<Integer> queueNumber = new ArrayList<Integer>(); /* * 产生一个号码,代表一个用户取号 因为产生号码和获取号码是不同线程对同一个数据进行操作,这样会产生问题,必须让他们互斥,所以加入同步 */ public synchronized Integer generateNumber() { queueNumber.add(lastNumber); return lastNumber++; } /* 窗口取得一个号码,代表依次为客户服务 */ public synchronized Integer fetchNumber() { Integer number = null; if (queueNumber.size() > 0) number = queueNumber.remove(0); return number; } }
NumberMechine:号码机器
/* * 1.整个系统中,取号机器只有一台,所以要设计成单例模式 * 2.该类中应该提供通过反问该类对象返回三个数字管理器对象的方法 */ package cn.itcast.Mr_Zhang.BankQueue; public class NumberMechine { /*构造函数私有化,禁止外部创建对象*/ private NumberMechine(){ } /*为外部提供一个访问本类对象的方法*/ private static final NumberMechine instance = new NumberMechine(); public static NumberMechine getNumberMechine(){ return instance; } /*创建普通、快速、VIP数字管理器对象并提供外部访问方法*/ private NumberManager commonNumber = new NumberManager(); private NumberManager expressNumber = new NumberManager(); private NumberManager VipNumber = new NumberManager(); public NumberManager getCommonNumber() { return commonNumber; } public NumberManager getExpressNumber() { return expressNumber; } public NumberManager getVipNumber() { return VipNumber; } }
Constants:常量
package cn.itcast.Mr_Zhang.BankQueue; public class Constants { public static final int SERVICE_TIME_MIN = 1000; public static final int SERVICE_TIME_MAX = 10000; public static final int COMMON_CUSTOMER_INTERVAL_TIME = 1; }
mainClass:模拟运行系统
package cn.itcast.Mr_Zhang.BankQueue; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; public class mainClass { public static void main(String[] args) { /*生成4个普通窗口并开启*/ for(int i = 1; i<=4; i++){ ServiceWindows commonWindow = new ServiceWindows(); commonWindow.setType(CustomerType.COMMON); commonWindow.setWindowId(i); commonWindow.start(); } /*生成1个快速窗口并开启*/ ServiceWindows expressWindow = new ServiceWindows(); expressWindow.setType(CustomerType.EXPRESS); expressWindow.start(); /*生成1个VIP窗口并开启*/ ServiceWindows vipWindow = new ServiceWindows(); vipWindow.setType(CustomerType.VIP); vipWindow.start(); /*按频率增加普通客户*/ Executors.newScheduledThreadPool(1).scheduleAtFixedRate( new Runnable(){ public void run(){ Integer serviceNumber = NumberMechine.getNumberMechine().getCommonNumber().generateNumber(); System.out.println("第" + serviceNumber + "号普通客户正在等待服务"); } }, 0, Constants.COMMON_CUSTOMER_INTERVAL_TIME, TimeUnit.SECONDS); /*按频率增加快速客户*/ Executors.newScheduledThreadPool(1).scheduleAtFixedRate( new Runnable(){ public void run(){ Integer serviceNumber = NumberMechine.getNumberMechine().getExpressNumber().generateNumber(); System.out.println("第" + serviceNumber + "号快速客户正在等待服务"); } }, 0, Constants.COMMON_CUSTOMER_INTERVAL_TIME * 2, TimeUnit.SECONDS); /*按频率增加VIP客户*/ Executors.newScheduledThreadPool(1).scheduleAtFixedRate( new Runnable(){ public void run(){ Integer serviceNumber = NumberMechine.getNumberMechine().getVipNumber().generateNumber(); System.out.println("第" + serviceNumber + "号VIP客户正在等待服务"); } }, 0, Constants.COMMON_CUSTOMER_INTERVAL_TIME * 6, TimeUnit.SECONDS); } }
----------------------
ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------详细请查看:http://edu.csdn.net
相关文章推荐
- 面试题:二叉树的层次遍历,包括定制树的建立
- 从程序员到CTO的Java技术路线
- 适用于Java程序员的通信顺序进程
- 程序员必看的十大电影
- “你最喜欢的程序员漫画”精选
- 从程序员到CTO的Java技术路线图 (转自安卓巴士)
- 黑马程序员_毕向东_Java基础视频教程学习笔记(二十一)
- 来个面试题:将1002格式转成一千零二
- 现在的全能程序员都是修炼出来的
- java面试--(生成随机数,获取重复次数最多,并且数是最大的一个,打印出来)
- 最近面试总结
- Android经典面试题
- 一位Erlang程序员的自白
- php面试常用算法
- 动态网页PHP程序员的优化调试技术和技巧
- 程序员眼中的UML
- 职场寓言-公司到底是谁的?
- 职场寓言-公司到底是谁的?
- 职场寓言-公司到底是谁的?
- Leetcode 难度及面试频率和算法