黑马程序员技术交流社区

标题: 今天学的张老师的银行调度系统,自己用1个小时打了一遍 [打印本页]

作者: Bule丶    时间: 2014-8-8 16:57
标题: 今天学的张老师的银行调度系统,自己用1个小时打了一遍
本帖最后由 Bule丶 于 2014-8-9 22:00 编辑
  1. 首先,第一个是管理号码的类
  2. /*********************************/
  3. package com.hans.bank1;
  4. import java.util.ArrayList;
  5. import java.util.List;
  6. /**
  7. * 号码管理者
  8. * @author hans
  9. *
  10. */
  11. public class NumberManager {
  12. private List<Integer> queueNumber = new ArrayList<Integer>(); //号码队列

  13. private int lastNumber = 1; //上一个号码 客户拿了一个号,得把号码送回去吧,然后在等待 号码是从1开始的

  14. //客户取号的方法
  15. public Integer generateNewNumber(){
  16.   queueNumber.add(lastNumber);
  17.   return lastNumber++;
  18. }

  19. /**
  20.   * 窗口叫号用的方法  
  21.   * @return
  22.   */
  23. public Integer fetchServiceNumber(){
  24.   Integer number = null;
  25.   if(queueNumber.size() > 0){
  26.    number = queueNumber.remove(0);
  27.   }
  28.   return number;
  29. }
  30. }
  31. //接下来是管理号码的类的管理者,相当于是一个机器,管理号码的类是软件
  32. /******************************/
  33. package com.hans.bank1;
  34. /**
  35. * 号码管理者所在的机器
  36. * @author hans
  37. *
  38. */
  39. public class NumberMachine {
  40. //机器肯定是单例模式的
  41. private static NumberMachine manchine = new NumberMachine();
  42. private NumberMachine(){
  43. }

  44. public static NumberMachine getInstance(){
  45.   return manchine;
  46. }

  47. private NumberManager commonManager = new NumberManager(); //普通客户号码管理
  48. private NumberManager expressManager = new NumberManager(); //快速客户号码管理
  49. private NumberManager vipManager = new NumberManager(); //vip客户号码管理

  50. /**
  51.   * get方法
  52.   * @return
  53.   */
  54. public NumberManager getCommonManager() {
  55.   return commonManager;
  56. }
  57. public NumberManager getExpressManager() {
  58.   return expressManager;
  59. }
  60. public NumberManager getVipManager() {
  61.   return vipManager;
  62. }
  63. }
  64. /*******************************/
  65. 接下来到了银行窗口,但是窗口肯定有类型,就用到了枚举
  66. package com.hans.bank1;
  67. /**
  68. * 窗口的类型,客户的类型
  69. * @author hans
  70. *
  71. */
  72. public enum CustomerType {
  73. COMMON,EXPRESS,VIP;

  74. public String toString(){
  75.   switch (this) {
  76.   case COMMON:
  77.    return "普通";
  78.   case EXPRESS:
  79.    return "快速";
  80.   case VIP:
  81.    return name();
  82.   }
  83.   return null;
  84. }
  85. }
  86. /***************************/
  87. //窗口类
  88. package com.hans.bank1;import java.util.Random;
  89. import java.util.concurrent.Executors;
  90. /**
  91. * 银行窗口  
  92. * @author hans
  93. *
  94. */
  95. public class ServiceWindow {

  96. //窗口应该有第几号  ,当前窗口的级别 是普通呢,还是快速的呢,还是vip的呢 所以我们需要2个属性  id 和 类型

  97. private int windowId = 1; //窗口的编号
  98. private CustomerType type = CustomerType.COMMON; //窗口的类型
  99. /**
  100.   * set方法   服务窗口默认是普通类型,可以set为别的类型  窗口编号也不是固定的  也需要set方法
  101.   * @param windowId
  102.   */
  103. public void setWindowId(int windowId) {
  104.   this.windowId = windowId;
  105. }
  106. public void setType(CustomerType type) {
  107.   this.type = type;
  108. }
  109. //窗口开始服务的方法
  110. public void start(){
  111.   Executors.newSingleThreadExecutor().execute(new Runnable(){
  112.    @Override
  113.    public void run() {
  114.     while(true){
  115.      switch (type) {
  116.      case COMMON:
  117.       commonService();
  118.       break;
  119.      case EXPRESS:
  120.       expressService();
  121.       break;
  122.      case VIP:
  123.       vipService();
  124.       break;
  125.      }
  126.     }
  127.    }
  128.   });
  129. }

  130. /*
  131.   * 普通用户窗口服务的方法
  132.   */
  133. private void commonService(){
  134.   String windowName = "第"+windowId+"号"+type+"窗口";
  135.   System.out.println(windowName + "开始取得任务!");
  136.   
  137.   Integer number = NumberMachine.getInstance().getCommonManager().fetchServiceNumber();//取得号码队列里的前面的号码
  138.   
  139.   if(number != null){ //如果为null,代表没人人来
  140.    System.out.println(windowName + "开始服务第" + number + "号普通客户!");
  141.    long beginTime = System.currentTimeMillis();
  142.    int maxRandom = Constants.MAX_SERVICE_TIME - Constants.MIN_SERVICE_TIME; //规定的最小1000毫秒和最大10000毫秒时间差 9000毫秒 也就是随机毫秒数
  143.    long maxServiceTime = new Random().nextInt(maxRandom)+1 + Constants.MIN_SERVICE_TIME; //此处,最小服务一秒,最大10秒  单位是毫秒
  144.    try {
  145.     new Thread().sleep(maxServiceTime); //线程睡眠的毫秒数  也就是服务的时长
  146.    } catch (InterruptedException e) {
  147.     e.printStackTrace();
  148.    }
  149.    long costTime = System.currentTimeMillis() - beginTime; //总共用时的时间 毫秒数
  150.    System.out.println(windowName + "服务普通客户用时" + costTime/1000 + "秒!");
  151.   }else{
  152.    System.out.println(windowName + "没有取到任务,休息一秒钟!");
  153.    try {
  154.     new Thread().sleep(1000);
  155.    } catch (InterruptedException e) {
  156.     e.printStackTrace();
  157.    }
  158.   }
  159. }
  160. /*
  161.   * 快速用户窗口服务的方法
  162.   */
  163. private void expressService(){
  164.   String windowName = "第"+windowId+"号"+type+"窗口";
  165.   System.out.println(windowName + "开始取得任务");
  166.   
  167.   Integer number = NumberMachine.getInstance().getExpressManager().fetchServiceNumber();//取得号码队列里的前面的号码
  168.   
  169.   if(number != null){ //如果为null,代表没人人来
  170.    System.out.println(windowName + "开始服务第" + number + "号" + type + "客户!");
  171.    long beginTime = System.currentTimeMillis();
  172.    try {
  173.     new Thread().sleep(Constants.MIN_SERVICE_TIME); //线程睡眠的毫秒数  也就是服务的时长 快速窗口就1秒钟
  174.    } catch (InterruptedException e) {
  175.     e.printStackTrace();
  176.    }
  177.    long costTime = System.currentTimeMillis() - beginTime; //总共用时的时间 毫秒数
  178.    System.out.println(windowName + "服务" + type + "客户用时" + costTime/1000 + "秒!");
  179.   }else{
  180.    System.out.println(windowName + "没有取到任务!");//快速窗口没有用户要去服务普通客户 不能休息
  181.    commonService();
  182.   }
  183. }
  184. /*
  185.   * vip用户窗口服务的方法
  186.   */
  187. private void vipService(){
  188.   String windowName = "第"+windowId+"号"+type+"窗口";
  189.   System.out.println(windowName + "开始取得任务");
  190.   
  191.   Integer number = NumberMachine.getInstance().getVipManager().fetchServiceNumber();//取得号码队列里的前面的号码
  192.   
  193.   if(number != null){ //如果为null,代表没人人来
  194.    System.out.println(windowName + "开始服务第" + number + "号" + type + "客户!");
  195.    long beginTime = System.currentTimeMillis();
  196.    int maxRandom = Constants.MAX_SERVICE_TIME - Constants.MIN_SERVICE_TIME; //规定的最小1000毫秒和最大10000毫秒时间差 9000毫秒 也就是随机毫秒数
  197.    long maxServiceTime = new Random().nextInt(maxRandom)+1 + Constants.MIN_SERVICE_TIME; //此处,最小服务一秒,最大10秒  单位是毫秒
  198.    try {
  199.     new Thread().sleep(maxServiceTime); //线程睡眠的毫秒数  也就是服务的时长
  200.    } catch (InterruptedException e) {
  201.     e.printStackTrace();
  202.    }
  203.    long costTime = System.currentTimeMillis() - beginTime; //总共用时的时间 毫秒数
  204.    System.out.println(windowName + "服务" + type + "客户用时" + costTime/1000 + "秒!");
  205.   }else{
  206.    System.out.println(windowName + "没有取到任务!"); //vip窗口没有用户要去服务普通客户 不能休息
  207.    commonService();
  208.   }
  209. }
  210. }

  211. /************************************/
  212. 窗口用到了一些常量,比如要求规定的最大时间啊,最小时间啊,这个常量类
  213. package com.hans.bank1;

  214. /**
  215. * 一些用到的常量
  216. * @author hans
  217. *
  218. */
  219. public class Constants {

  220. final public static int MIN_SERVICE_TIME = 1000; //每个窗口最短服务时间
  221. final public static int MAX_SERVICE_TIME = 10000; //每个窗口最长服务时间
  222. final public static int INTERVAL_TIME = 1; //客户进入间隔时间

  223. }
  224. /********************/
  225. 接下来是测试类了
  226. package com.hans.bank1;

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

  229. /**
  230. * 测试类
  231. * @author hans
  232. *
  233. */
  234. public class MainClass {

  235. /**
  236. * @param args
  237. */
  238. public static void main(String[] args) {
  239. /**
  240. * 6个窗口初始化
  241. */
  242. for (int i = 1; i < 5; i++) {
  243. ServiceWindow commonWindow = new ServiceWindow(); //4个普通窗口
  244. commonWindow.setWindowId(i); //set一下窗口id
  245. commonWindow.start(); //默认就是普通窗口 不用在set类型 开启服务
  246. }

  247. ServiceWindow expressWindow = new ServiceWindow(); //4个普通窗口
  248. expressWindow.setType(CustomerType.EXPRESS); //设置窗口类型 快速类型
  249. expressWindow.start(); //默开启服务


  250. ServiceWindow vipWindow = new ServiceWindow(); //4个普通窗口
  251. vipWindow.setType(CustomerType.VIP); //设置窗口类型 VIP类型
  252. vipWindow.start(); //开启服务


  253. /**
  254. * 客户初始化
  255. */
  256. //用线程池的计时器
  257. //生成的普通客户
  258. Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
  259. new Runnable() {
  260. @Override
  261. public void run() {
  262. Integer number = NumberMachine.getInstance().getCommonManager().generateNewNumber(); //生成普通客户
  263. System.out.println("第"+number+"位普通客户等待服务!");
  264. }
  265. },
  266. 0,
  267. Constants.INTERVAL_TIME,
  268. TimeUnit.SECONDS);
  269. //生成的快速客户
  270. Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
  271. new Runnable() {
  272. @Override
  273. public void run() {
  274. Integer number = NumberMachine.getInstance().getExpressManager().generateNewNumber(); //生成快速客户
  275. System.out.println("第"+number+"位快速客户等待服务!");
  276. }
  277. },
  278. 0,
  279. Constants.INTERVAL_TIME*3,
  280. TimeUnit.SECONDS);
  281. //生成的vip客户
  282. Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
  283. new Runnable() {
  284. @Override
  285. public void run() {
  286. Integer number = NumberMachine.getInstance().getVipManager().generateNewNumber(); //生成vip客户
  287. System.out.println("第"+number+"位vip客户等待服务!");
  288. }
  289. },
  290. 0,
  291. Constants.INTERVAL_TIME*6,
  292. TimeUnit.SECONDS);

  293. }

  294. }

复制代码


bank1.rar

13.79 KB, 下载次数: 486

源码


作者: Bule丶    时间: 2014-8-8 16:59
/************************************/
窗口用到了一些常量,比如要求规定的最大时间啊,最小时间啊,这个常量类
package com.hans.bank1;

/**
* 一些用到的常量
* @author hans
*
*/
public class Constants {

final public static int MIN_SERVICE_TIME = 1000; //每个窗口最短服务时间
final public static int MAX_SERVICE_TIME = 10000; //每个窗口最长服务时间
final public static int INTERVAL_TIME = 1; //客户进入间隔时间

}
/********************/
接下来是测试类了
package com.hans.bank1;

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

/**
* 测试类
* @author hans
*
*/
public class MainClass {

/**
* @param args
*/
public static void main(String[] args) {
/**
* 6个窗口初始化
*/
for (int i = 1; i < 5; i++) {
ServiceWindow commonWindow = new ServiceWindow(); //4个普通窗口
commonWindow.setWindowId(i); //set一下窗口id
commonWindow.start(); //默认就是普通窗口 不用在set类型 开启服务
}

ServiceWindow expressWindow = new ServiceWindow(); //4个普通窗口
expressWindow.setType(CustomerType.EXPRESS); //设置窗口类型 快速类型
expressWindow.start(); //默开启服务


ServiceWindow vipWindow = new ServiceWindow(); //4个普通窗口
vipWindow.setType(CustomerType.VIP); //设置窗口类型 VIP类型
vipWindow.start(); //开启服务


/**
* 客户初始化
*/
//用线程池的计时器
//生成的普通客户
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
new Runnable() {
@Override
public void run() {
Integer number = NumberMachine.getInstance().getCommonManager().generateNewNumber(); //生成普通客户
System.out.println("第"+number+"位普通客户等待服务!");
}
},
0,
Constants.INTERVAL_TIME,
TimeUnit.SECONDS);
//生成的快速客户
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
new Runnable() {
@Override
public void run() {
Integer number = NumberMachine.getInstance().getExpressManager().generateNewNumber(); //生成快速客户
System.out.println("第"+number+"位快速客户等待服务!");
}
},
0,
Constants.INTERVAL_TIME*3,
TimeUnit.SECONDS);
//生成的vip客户
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
new Runnable() {
@Override
public void run() {
Integer number = NumberMachine.getInstance().getVipManager().generateNewNumber(); //生成vip客户
System.out.println("第"+number+"位vip客户等待服务!");
}
},
0,
Constants.INTERVAL_TIME*6,
TimeUnit.SECONDS);

}

}



作者: Bule丶    时间: 2014-8-8 17:01
因为今天才学的,还没有进行优化
作者: Sunflower丶    时间: 2014-8-8 19:15
看来要加油了:'(
作者: Bule丶    时间: 2014-8-8 21:02
Sunflower丶 发表于 2014-8-8 19:15
看来要加油了

我自己默默讲了这个和交通灯,感觉讲起来思路还是可以的
作者: lcycr    时间: 2014-8-8 21:07
给力啊楼主
作者: .Mч┞尛__洋    时间: 2014-8-8 21:10
我当时学的时候 也是敲了 好几遍
作者: Bule丶    时间: 2014-8-8 21:12
.Mч┞尛__洋 发表于 2014-8-8 21:10
我当时学的时候 也是敲了 好几遍

确实感觉思路最重要了,思路理解了可以根据思路慢慢打,我再打一遍吧,巩固一下
作者: jwx555    时间: 2014-8-8 21:21
学了一个小时,然后自己写的
还是说你自己花了一个小时写的?

大概看了下,貌似完全照抄的感觉。老师课上现场写的,可能不是太完美,你可以试着自己进行优化
作者: .Mч┞尛__洋    时间: 2014-8-8 21:22
Bule丶 发表于 2014-8-8 21:12
确实感觉思路最重要了,思路理解了可以根据思路慢慢打,我再打一遍吧,巩固一下 ...

对 多敲几遍 有好处   我只学习思路  代码很好实现
作者: Bule丶    时间: 2014-8-8 21:48
jwx555 发表于 2014-8-8 21:21
学了一个小时,然后自己写的
还是说你自己花了一个小时写的?

今天学完后用一个小时打出来滴,嘿嘿,,是不是时间有点长了
作者: Bule丶    时间: 2014-8-8 21:50
.Mч┞尛__洋 发表于 2014-8-8 21:22
对 多敲几遍 有好处   我只学习思路  代码很好实现

嗯嗯,多敲敲总是有好处的,
作者: 继续悲伤    时间: 2014-8-8 21:57
你都学完了啊。这个我还没有看呢1!感觉容易吗?
作者: Bule丶    时间: 2014-8-8 23:00
继续悲伤 发表于 2014-8-8 21:57
你都学完了啊。这个我还没有看呢1!感觉容易吗?

感觉并不难,今天学的,刚刚把逻辑实现思路都打了一边,不过想能直接自己打出来这个肯定不是一次就可以的,至少我是不行
作者: z-翔    时间: 2014-8-8 23:02
还没有看到
不过看了楼主写的代码
感觉好长
瞬间崩溃...
作者: Bule丶    时间: 2014-8-8 23:11
z-翔 发表于 2014-8-8 23:02
还没有看到
不过看了楼主写的代码
感觉好长

有源码,你可以看下,刚刚打的思路给你看看,不喜勿喷蛤,嘿嘿
/**
                 * 经常去银行的知道银行服务的业务,像我这几乎不去银行的现在也了解了银行的业务,嘿嘿
                 * 银行调度服务,当客户去了银行,得领取排队号,那么,客户也是分等级的,可以分普通用户,快速用户(缴费的,水电费啊,什么的),还有vip大客户
                 * 那么领取派对号,肯定是可选的了,号码也有3个类型,普通,快速,vip
                 * 那么,银行有很多窗口,那么窗口也可以分类型,和编号,比如1-4号是处理普通客户的窗口,5号是处理快速客户的窗口,6号是vip窗口,处理vip客户
                 * 那么没有快速和vip的客户,也不能闲着,所以当没有快速客户或者vip客户那么就处理普通客户,
                 * 那么一切都是客户开始的,但是客户是领取了排队号的才是客户,其他人员不是,那么就可以直接定义排队号来代替客户,
                 * 从上,我们总结出一个东西,现实中银行有取票器,在取票器里可以选择票的类型进行取票,那么我们可以定义票类,还有一个取票机器,用来管理所有票类,还有服务的窗口,每个窗口和票都有类型
                 * 类型是固定的,我们可以定义成枚举
                 * 首先我们要知道持有数据的一方都会有操作这个数据的方法,那么票类,每一个类别,肯定是有一组票,也就是一个票的集合,在当前票类里应该有生成票,也就是客户来取票,还有窗口叫号,就是删除票
                 * 的方法
                 * 接下来说票的管理类,既然有3种类型,我们就可以在票的管理类里定义3个选项,就像取票器可以选择不同的类型进行拿票,那么这个取票器就定义成单例模式,节省了内存的占用
                 * 接下来就该有窗口了,窗口,是不是得有自己的编号,也就是id,是不是得有自己的类型,也就是普通或者快速或者vip窗口,一个服务窗口,肯定的有开始服务的方法,就像每天6点开始服务,
                 * 那么窗口,判断自己是什么类型,然后叫对应类型的号是不是,因为窗口都是一样的,不一样的只是窗口上挂着的类别牌子而已,那么判断了自己是什么类型的了,那么服务人员是不是全是一样的操作啊
                 * 不一样的就是快速窗口在来快速的客户就先处理快速客户,vip同样是如此,那么我们可以定义3个方法,分别实现3个服务,既然说道了服务客户
                 * 当窗口叫票的时候,如果没有客户也就是说没有票,那么就可以偷懒咯,嘿嘿,然后休息一会啊,抽根烟啊,那么有票就得处理了,看看窗口怎么服务
                 * 服务那么肯定有处理服务的时间,开始时间,服务时间,结束时间,那么这个系统里定义了最短时间和最大时间,那么我们为了方便管理,是不是要把这两个时间定义到一个常量里面,比如服务处理最长时间为10秒
                 * 最短时间为1秒
                 * 那么服务时间是随机的,我们可以定义一个随机数,那么随机数要随机的时间是什么呢?我们可以用最大时间和最小时间的差,也就是9秒内的随机,那么随机数是小数,向下取整,我们就给他加1
                 * 但是有可能是0,我们就加上最短的世间,这样,最短时间就是1秒处理完了,我们可以给一个友好的提示,当前窗口开始为谁服务啊,那么服务用的时间,我们可以用线程睡眠来控制,睡眠时间就是随机出来的毫秒数
                 * 服务完了,提醒一下吧,几号窗口什么类型的服务了什么类型的第几号客户,
                 * 接下来就是快速窗口了,实现是一样的,不一样的就是快速,一秒一个,当没有快速客户的时候要服务普通客户,就调用服务普通客户的方法好了
                 * 接下来就是vip窗口,实现也是一样的,不一样的就是没有vip客户的时候要服务普通客户,就调用服务普通客户的方法好了
                 *
                 * 那么现在差的就是银行了,相当于一个测试类
                 * 循环创建4个普通窗口,因为窗口里有类型,默认就是普通的,所以设置一下窗口号码就可以
                 * 然后我们来创建客户,客户分普通,快速,vip客户,比例是1:3:6 也就是说1秒一个普通客户,3秒一个快速客户,6秒一个vip客户
                 * 我们可以用线程池的定时器来实现
                 * 创建一个定时器,客户取票肯定是通过取票器啊,然后选择票啊,我们就设定这个取票器都是普通客户,调用票管理者的方法,然后里面有不同类别的票,调用普通的票,然后调用票的生成新的票的方法,那么就取到票了
                 * 返回的是取到的票的号码,我们可以提示几号客户等待服务啊。
                 * 定时器有4个参数,第一个是Runnable接口实现类重写run方法,取票就可以写在这里,第二个参数就是几秒后执行,第三个是没隔几秒执行一次,第四个就是参数的类型了,是年啊,还是天啊,还是月啊,还是分啊秒啊,我们用的是秒
                 * 快速客户和vip客户和普通客户创建一样,只是调用时间是3秒和6秒一次,取票器里选择的也是快速和vip类型的票
                 */
作者: 张星    时间: 2014-8-8 23:30
正在学习中!
作者: Bule丶    时间: 2014-8-8 23:38
张星 发表于 2014-8-8 23:30
正在学习中!

加油加油,我面试还没把握呢,努力复习集合框架
作者: wawsc5354524    时间: 2014-8-9 01:05
我的个神,大神牛皮,光是这些代码都够我打好长一阵子了,小弟佩服!
作者: Bule丶    时间: 2014-8-9 15:37
wawsc5354524 发表于 2014-8-9 01:05
我的个神,大神牛皮,光是这些代码都够我打好长一阵子了,小弟佩服!

要了解思路,代码就跟着出来了
作者: dreamseekerkun    时间: 2014-8-9 21:54
还没看到,刚看到集合框架,感觉很复杂的样子,不过楼主说得对,理清思路,代码就出来了
作者: 心之信子    时间: 2014-8-9 22:28
你们感觉容容易吗
作者: Bule丶    时间: 2014-8-9 22:31
心之信子 发表于 2014-8-9 22:28
你们感觉容容易吗

刚开始第一遍肯定不是太顺,我是在讲的时候讲一集,然后打一次,然后都讲完了,我也打完了,然后自己在重新打一次,然后就没打过第三次了




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2