银行业务调度系统
2014-03-12 00:50
295 查看
今天在网上看到一道关于银行业务调度系统的题目,感觉有点意思,就动手写了写代码,记录一下。
题目:模拟实现银行业务调度系统逻辑,具体需求如下:
*银行内有6个业务窗口,1 - 4号窗口为普通窗口,5号窗口为快速窗口,6号窗口为VIP窗口。
*有三种对应类型的客户:VIP客户,普通客户,快速客户(办理如交水电费、电话费之类业务的客户)。
*异步随机生成各种类型的客户,生成各类型用户的概率比例为:
VIP客户 :普通客户 :快速客户 = 1 :6 :3。
*客户办理业务所需时间有最大值和最小值,在该范围内随机设定每个VIP客户以及普通客户办理业务所需的时间,
快速客户办理业务所需时间为最小值(提示:办理业务的过程可通过线程Sleep的方式模拟)。
*各类型客户在其对应窗口按顺序依次办理业务。
当VIP(6号)窗口和快速业务(5号)窗口没有客户等待办理业务的时候,这两个窗口可以处理普通客户的业务,
而一旦有对应的客户等待办理业务的时候,则优先处理对应客户的业务。
随机生成客户时间间隔以及业务办理时间最大值和最小值自定,可以设置。
不要求实现GUI,只考虑系统逻辑实现,可通过Log方式展现程序运行结果。
对题目进行分析,
有三种类型的客户,他们的身份(职责)并不相同,但是他们的方法确实相同的,所以定义了三个方法相同的接口IVIPCustom,IExpressCustom和ICommonCustom。
package com.garychow.interfaces; public interface IVIPCustom { public int getNeedsTime(); public String getName(); }
package com.garychow.interfaces; public interface IExpressCustom { public int getNeedsTime(); public String getName(); }
package com.garychow.interfaces; public interface ICommonCustom { public int getNeedsTime(); public String getName(); }
三类客户分别对应了三种职责的窗口,普通窗口,快速窗口和VIP窗口。所以,也需要三个接口,ICommonServiceWindow,IExpressServiceWindow和IVIPServiceWindow。
package com.garychow.interfaces; public interface ICommonServiceWindow { public boolean service(ICommonCustom custom); }
package com.garychow.interfaces; public interface IExpressServiceWindow { public boolean service(IExpressCustom custom); }
package com.garychow.interfaces; public interface IVIPServiceWindow { public boolean service(IVIPCustom custom); }
最后,有一个调度业务窗口和用户的系统,同时根据题意,是通过号码来进行管理调度的,我把他们的职责归纳到一起,所以有一个INumberMachine接口。
package com.garychow.interfaces; // INumberMachine是整个系统的调度类,负责管理维护和处理服务顺序等 public interface INumberMachine { // 产生一个普通客户 public void generateCommonCustom(); // 产生一个VIP客户 public void generateVIPCustom(); // 产生一个快速客户 public void generateExpressCustom(); // 为下一个普通客户服务 public void serviceNextCommonCustom(); // 为下一个VIP客户服务 public void serviceNextVIPCustom(); // 为下一个快速客户服务 public void serviceNextExpressCustom(); }
接口声明到此就结束了。
现在需要来考虑具体实现了:
首先需要定义常量:
package com.garychow.classes; public class Constants { public static final int GENERATE_INTERVAL_TIME = 1; public static final int CUSTOM_NEEDS_TIME_MAX = 6; public static final int CUSTOM_NEEDS_TIME_MIN = 2; }
然后需要实现ICommonCustom,IExpressCustom和IVIPCustom接口。
package com.garychow.classes; import com.garychow.interfaces.ICommonCustom; public class CommonCustom implements ICommonCustom { @Override public int getNeedsTime() { return time; } @Override public String getName() { return name; } private int time = (int)((Math.random() * (Constants.CUSTOM_NEEDS_TIME_MAX - Constants.CUSTOM_NEEDS_TIME_MIN) + Constants.CUSTOM_NEEDS_TIME_MIN) * 1000); private String name = ++number + "号普通客户"; private static int number = 0; }
package com.garychow.classes; import com.garychow.interfaces.IVIPCustom; public class VIPCustom implements IVIPCustom { @Override public int getNeedsTime() { return time; } @Override public String getName() { return name; } private int time = (int)((Math.random() * (Constants.CUSTOM_NEEDS_TIME_MAX - Constants.CUSTOM_NEEDS_TIME_MIN) + Constants.CUSTOM_NEEDS_TIME_MIN) * 1000); private String name = ++number + "号VIP客户"; private static int number = 0; }
package com.garychow.classes; import com.garychow.interfaces.IExpressCustom; public class ExpressCustom implements IExpressCustom { @Override public int getNeedsTime() { return time; } @Override public String getName() { return name; } private int time = (Constants.CUSTOM_NEEDS_TIME_MIN * 1000); private String name = ++number + "号快速顾客"; private static int number = 0; }
普通客户可以由任意一个窗口服务,而VIP客户和快速客户只能通过相应的窗口获得服务,因为,我认为这个可以设计为一个责任链,把普通客户交给链头,直到有窗口能服务客户或者都暂时不能服务为止。因为设计一个抽象类AResponsibilityChainCommonWindow实现ICommonServiceWindow接口。
package com.garychow.classes; import com.garychow.interfaces.ICommonCustom; import com.garychow.interfaces.ICommonServiceWindow; public abstract class AResponsibilityChainCommonWindow implements ICommonServiceWindow { private ICommonServiceWindow nextCommonServiceWindow; public ICommonServiceWindow getNextCommonServiceWindow() { return nextCommonServiceWindow; } public void setNextCommonServiceWindow(ICommonServiceWindow nextCommonServiceWindow) { this.nextCommonServiceWindow = nextCommonServiceWindow; } @Override public boolean service(ICommonCustom custom) { if (null != nextCommonServiceWindow) { return nextCommonServiceWindow.service(custom); } return false; } }
责任链已经搞定了,现在发现调度系统需要了解各个窗口的状态,好分配客户到窗口去。这是一个典型的观察者,而窗口们就是被观察者。因为实现一个观察者类WindowObserver,由它去通知INumberMachine。
package com.garychow.classes; import com.garychow.interfaces.INumberMachine; public class WindowObserver { public static WindowObserver getInstance() { return WindowObserverHolder.wo; } private static class WindowObserverHolder { public static final WindowObserver wo = new WindowObserver(); } private WindowObserver() { } public void commonWindowServiceFinish() { nm.serviceNextCommonCustom(); } public void vipWindowServiceFinish() { nm.serviceNextVIPCustom(); } public void expressWindowServiceFinish() { nm.serviceNextExpressCustom(); } private INumberMachine nm = NumberMachine.getInstance(); }
到这里整体的思路全部都清晰了,下面只要把方法都实现出来就好了。
类CommonWindow继承AResponsibilityChainCommonWindow,实现服务客户的方法。
package com.garychow.classes; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import com.garychow.interfaces.ICommonCustom; public class CommonWindow extends AResponsibilityChainCommonWindow { public CommonWindow(String name) { this.name = name; } @Override public boolean service(ICommonCustom custom) { if (isServicing) { return super.service(custom); } isServicing = true; final ICommonCustom fCustom = custom; executor.execute(new Runnable() { @Override public void run() { try { long beginTime = System.nanoTime(); System.out.println(name + "开始为普通顾客:" + fCustom.getName() + "服务"); Thread.sleep(fCustom.getNeedsTime()); long endTime = System.nanoTime(); System.out.println(name + "服务顾客" + fCustom.getName() + "完毕,服务时间为:" + (endTime - beginTime)); } catch (InterruptedException e) { } finally { isServicing = false; WindowObserver.getInstance().commonWindowServiceFinish(); } } }); return true; } private Executor executor = Executors.newSingleThreadExecutor(); private boolean isServicing; private String name; }
VIPServiceWindow也继承AResponsibilityChainCommonWindow类,因为它也是处理普通客户的链上的一环,同时要实现IVIPServiceWindow接口,处理VIP客户服务。
package com.garychow.classes; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import com.garychow.interfaces.ICommonCustom; import com.garychow.interfaces.IVIPCustom; import com.garychow.interfaces.IVIPServiceWindow; public class VIPServiceWindow extends AResponsibilityChainCommonWindow implements IVIPServiceWindow { public VIPServiceWindow(String name) { this.name = name; } @Override public boolean service(ICommonCustom custom) { if (isServicing) { return super.service(custom); } isServicing = true; final ICommonCustom fCustom = custom; executor.execute(new Runnable() { @Override public void run() { try { long beginTime = System.nanoTime(); System.out.println(name + "开始为普通顾客:" + fCustom.getName() + "服务"); Thread.sleep(fCustom.getNeedsTime()); long endTime = System.nanoTime(); System.out.println(name + "服务顾客" + fCustom.getName() + "完毕,服务时间为:" + (endTime - beginTime)); } catch (InterruptedException e) { } finally { isServicing = false; WindowObserver.getInstance().commonWindowServiceFinish(); } } }); return true; } @Override public boolean service(IVIPCustom custom) { if (isServicing) { return false; } isServicing = true; final IVIPCustom fCustom = custom; executor.execute(new Runnable() { @Override public void run() { try { long beginTime = System.nanoTime(); System.out.println(name + "开始为VIP顾客:" + fCustom.getName() + "服务"); Thread.sleep(fCustom.getNeedsTime()); long endTime = System.nanoTime(); System.out.println(name + "服务顾客" + fCustom.getName() + "完毕,服务时间为:" + (endTime - beginTime)); } catch (InterruptedException e) { } finally { isServicing = false; WindowObserver.getInstance().vipWindowServiceFinish(); } } }); return true; } private Executor executor = Executors.newSingleThreadExecutor(); private boolean isServicing; private String name; }
同样的,ExpressServiceWindow和VIPServiceWdinow类似。
package com.garychow.classes; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import com.garychow.interfaces.ICommonCustom; import com.garychow.interfaces.IExpressCustom; import com.garychow.interfaces.IExpressServiceWindow; public class ExpressServiceWindow extends AResponsibilityChainCommonWindow implements IExpressServiceWindow { public ExpressServiceWindow(String name) { this.name = name; } @Override public boolean service(IExpressCustom custom) { if (isServicing) { return false; } isServicing = true; final IExpressCustom fCustom = custom; executor.execute(new Runnable() { @Override public void run() { try { long beginTime = System.nanoTime(); System.out.println(name + "开始为快速顾客:" + fCustom.getName() + "服务"); Thread.sleep(fCustom.getNeedsTime()); long endTime = System.nanoTime(); System.out.println(name + "服务顾客" + fCustom.getName() + "完毕,服务时间为:" + (endTime - beginTime)); } catch (InterruptedException e) { } finally { isServicing = false; WindowObserver.getInstance().expressWindowServiceFinish(); } } }); return true; } @Override public boolean service(ICommonCustom custom) { if (isServicing) { return super.service(custom); } isServicing = true; final ICommonCustom fCustom = custom; executor.execute(new Runnable() { @Override public void run() { try { long beginTime = System.nanoTime(); System.out.println(name + "开始为普通顾客:" + fCustom.getName() + "服务"); Thread.sleep(fCustom.getNeedsTime()); long endTime = System.nanoTime(); System.out.println(name + "服务顾客" + fCustom.getName() + "完毕,服务时间为:" + (endTime - beginTime)); } catch (InterruptedException e) { } finally { isServicing = false; WindowObserver.getInstance().commonWindowServiceFinish(); } } }); return true; } private Executor executor = Executors.newSingleThreadExecutor(); private boolean isServicing; private String name; }
写到这里,只需要把调度系统给实现就好了。代码如下:
package com.garychow.classes; import java.util.Queue; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.LinkedBlockingQueue; import com.garychow.interfaces.ICommonCustom; import com.garychow.interfaces.ICommonServiceWindow; import com.garychow.interfaces.IExpressCustom; import com.garychow.interfaces.IExpressServiceWindow; import com.garychow.interfaces.INumberMachine; import com.garychow.interfaces.IVIPCustom; import com.garychow.interfaces.IVIPServiceWindow; public class NumberMachine implements INumberMachine { private static class NumberMachineHolder { public final static NumberMachine nm = new NumberMachine(); } private NumberMachine() { executor = Executors.newSingleThreadExecutor(); commonCustoms = new LinkedBlockingQueue<ICommonCustom>(); vipCustoms = new LinkedBlockingQueue<IVIPCustom>(); expressCustoms = new LinkedBlockingQueue<IExpressCustom>(); AResponsibilityChainCommonWindow cw1 = new CommonWindow("一号普通窗口"); AResponsibilityChainCommonWindow cw2 = new CommonWindow("二号普通窗口"); AResponsibilityChainCommonWindow cw3 = new CommonWindow("三号普通窗口"); AResponsibilityChainCommonWindow cw4 = new CommonWindow("四号普通窗口"); VIPServiceWindow vw = new VIPServiceWindow("VIP窗口"); ExpressServiceWindow ew = new ExpressServiceWindow("快速窗口"); cw1.setNextCommonServiceWindow(cw2); cw2.setNextCommonServiceWindow(cw3); cw3.setNextCommonServiceWindow(cw4); cw4.setNextCommonServiceWindow(ew); ew.setNextCommonServiceWindow(vw); commonServiceWindowChainHeader = cw1; expressServiceWindow = ew; vipServiceWindow = vw; } public static INumberMachine getInstance() { return NumberMachineHolder.nm; } @Override public void generateCommonCustom() { ICommonCustom custom = new CommonCustom(); commonCustoms.offer(custom); serviceNextCommonCustom(); } @Override public void generateVIPCustom() { IVIPCustom custom = new VIPCustom(); vipCustoms.offer(custom); serviceNextVIPCustom(); } @Override public void generateExpressCustom() { IExpressCustom custom = new ExpressCustom(); expressCustoms.offer(custom); serviceNextExpressCustom(); } @Override public void serviceNextCommonCustom() { executor.execute(new Runnable() { @Override public void run() { serviceNextCommonCustom(commonServiceWindowChainHeader); } }); } @Override public void serviceNextVIPCustom() { executor.execute(new Runnable() { @Override public void run() { if (!serviceNextVIPCustom(vipServiceWindow)) { serviceNextCommonCustom(vipServiceWindow); } } }); } @Override public void serviceNextExpressCustom() { executor.execute(new Runnable() { @Override public void run() { if (!serviceNextExpressCustom(expressServiceWindow)) { serviceNextCommonCustom(expressServiceWindow); } } }); } private boolean serviceNextCommonCustom(ICommonServiceWindow window) { boolean isServiced = false; if (!commonCustoms.isEmpty()) { ICommonCustom custom = commonCustoms.element(); if (isServiced = window.service(custom)) { commonCustoms.poll(); } } return isServiced; } private boolean serviceNextExpressCustom(IExpressServiceWindow window) { boolean isServiced = false; if (!expressCustoms.isEmpty()) { IExpressCustom custom = expressCustoms.element(); if (isServiced = window.service(custom)) { expressCustoms.poll(); } } return isServiced; } private boolean serviceNextVIPCustom(IVIPServiceWindow window) { boolean isServiced = false; if (!vipCustoms.isEmpty()) { IVIPCustom custom = vipCustoms.element(); if (isServiced = window.service(custom)) { vipCustoms.poll(); } } return isServiced; } private final Executor executor; private final Queue<ICommonCustom> commonCustoms; private final Queue<IVIPCustom> vipCustoms; private final Queue<IExpressCustom> expressCustoms; private final AResponsibilityChainCommonWindow commonServiceWindowChainHeader; private final ExpressServiceWindow expressServiceWindow; private final VIPServiceWindow vipServiceWindow; }
最后,写出场景类调用就可以模拟银行调度系统了。
package com.garychow.classes; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import com.garychow.interfaces.INumberMachine; public class Context { public static void main(String[] args) { final INumberMachine nm = NumberMachine.getInstance(); Executors.newScheduledThreadPool(1).scheduleAtFixedRate(new Runnable() { @Override public void run() { double random = Math.random(); if (random < 0.1) { nm.generateVIPCustom(); } else if (random >= 0.1 && random < 0.4) { nm.generateExpressCustom(); } else { nm.generateCommonCustom(); } } }, 0, Constants.GENERATE_INTERVAL_TIME, TimeUnit.SECONDS); } }
到此,这个题目就算完全做完了。
相关文章推荐
- 自定义dialog的布局样式
- vxworks6.6+workbench3.0+vmware工具链
- 【grunt第一弹】30分钟学会使用grunt打包前端代码
- hdu1232-我的第一道并查集
- Maven 2 for Eclipse配置全攻略(Windows篇)
- Android学习之——APP番茄工作法——小结(1)
- Java虚拟机工作原理详解
- codeforces#234_div2_D Dima and Bacteria floyd+并查集
- codeforces#234_div2_D Dima and Bacteria floyd+并查集
- 根据源图片缩放保留透明部分
- UUID工具类
- 日志记录最佳实践
- 【VMCloud云平台】SCVMM配置(二)创建一片云
- 【VMCloud云平台】SCVMM配置(二)创建一片云
- ZOJ 3725 Painting Storages DP
- 【leetcode题解】5 - Surrounded Regions
- crtmpserver 在VS2010下的build
- Bookmarklet
- hbase介绍
- 按钮控制ViewPager的左右翻页,保留原有的动画效果