模拟银行业务调度系统逻辑
需求
模拟实现银行业务调度系统逻辑,具体需求如下:
银行内有6个业务窗口,1 - 4号窗口为普通窗口,5号窗口为快速窗口,6号窗口为VIP窗口。
有三种对应类型的客户:VIP客户,普通客户,快速客户(办理如交水电费、电话费之类业务的客户)。
异步随机生成各种类型的客户,生成各类型用户的概率比例为:
VIP客户 :普通客户 :快速客户 = 1 :6 :3。
客户办理业务所需时间有最大值和最小值,在该范围内随机设定每个VIP客户以及普通客户办理业务所需的时间,快速客户办理业务所需时间为最小值(提示:办理业务的过程可通过线程Sleep的方式模拟)。
各类型客户在其对应窗口按顺序依次办理业务。
当VIP(6号)窗口和快速业务(5号)窗口没有客户等待办理业务的时候,这两个窗口可以处理普通客户的业务,而一旦有对应的客户等待办理业务的时候,则优先处理对应客户的业务。
随机生成客户时间间隔以及业务办理时间最大值和最小值自定,可以设置。
不要求实现GUI,只考虑系统逻辑实现,可通过Log方式展现程序运行结果。
分析
我们知道客户去银行办理业务,首先要去取号机取号,然后等待窗口叫号,那么窗口是通过什么叫号的呢,就是根据取号机内部产生和维护的不同的业务队列来完成的
所以
涉及的对象有:业务窗口、客户、取号机、业务类型以及取号机内部维护的业务队列
为了简化设计,用字符串形式代替客户信息,主要实现系统逻辑为主
面向对象分析与设计
业务类型BusinessType类:
采用枚举的方式,创建3个实例分别表示普通业务、快速业务、VIP业务
内部维护的业务队列Queue类:
内部维护一个集合用来存放队列中的客户信息
以及一个整型变量用来表示当天的客户队列号
实现加入一个客户到队列的方法
以及从队列中取出一个客户的方法(即叫号过程)
取号机TicketMachine类:
简化编程,我们将取号机设计成一个单例
内部维护三个不同业务类型的队列
对外提供取号方法给用户
提供获取队列方法给业务窗口
业务窗口Windows类:
业务窗口属性有:业务类型及窗口编号
对外提供开始业务的方法供银行调度
思考:
在对业务窗口进行设计的时候发现,虽然各窗口同属一类,但在提供服务的过程不尽相同,所以考虑的两种实现方式,如图
- 第一种就是考虑到在开展业务的时候各窗口的代码有不同之处,所以考虑用这种方式来设计,将不同的业务类型的窗口分配到不同的类
- 第二种是直接将所有业务类型的服务代码写在同一个类中
由于不太懂设计模式,个人的感觉是,这里主要实现的是系统逻辑,所以每个窗口的服务代码差异并没有想象的大,故采用第二种方式
如果是一个比较系统的需要长期维护的项目,我会采用第一种,确保每个类的单一功能
代码实现
业务类型BusinessType类:
1: /**
2: * 业务类型
3: * @author Shawn
4: *
5: */
6: public enum BusinessType {
7: GENERAL,//普通业务类型
8: QUICK,//快速业务类型
9: VIP;//VIP业务类型
10:
11: @Override
12: public String toString() {
13: switch(this){
14: case GENERAL:
15: return "普通";
16: case QUICK:
17: return "快速";
18: case VIP:
19: return "VIP";
20: }
21: return null;
22: }
23: }
用户队列Queue类:
1: /**
2: * 用户队列
3: * @author Shawn
4: *
5: */
6: public class Queue {
7:
8: private BusinessType businessType;//队列的业务类型
9: private int customerNum = 1;//记录用户队列号
10: List<String> queue = new LinkedList<String>();//队列载体
11:
12: public Queue(BusinessType businessType) {
13: super();
14: this.businessType = businessType;
15: }
16:
17: //产生新的号码,加入到队列
18: public synchronized String generateNewCustomer(){
19: String name = businessType+"客户_"+(customerNum++)+"号";
20: if(queue.add(name))
21: return name;
22: else
23: return null;
24: }
25:
26: //从队列中取出第一个客户
27: public synchronized String getCustomer(){
28: if(!isEmpty())
29: return queue.remove(0);
30: else
31: return null;
32: }
33:
34: //判断队列是否为空,即是否有客户等待业务
35: public synchronized boolean isEmpty(){
36: if(queue.size() > 0)
37: return false;
38: else
39: return true;
40: }
41: }
取号机TicketMachine类:
1: /**
2: * 取号机
3: * @author Shawn
4: *
5: */
6: public class TicketMachine {
7:
8: //内部维护的三个业务队列
9: private Queue generalQueue = new Queue(BusinessType.GENERAL);
10: private Queue quickQueue = new Queue(BusinessType.QUICK);
11: private Queue vipQueue = new Queue(BusinessType.VIP);
12:
13: //获取相关业务队列的接口
14: public Queue getQueue(BusinessType businessType){
15: switch(businessType){
16: case GENERAL:
17: return generalQueue;
18: case QUICK:
19: return quickQueue;
20: case VIP:
21: return vipQueue;
22: }
23: return null;
24: }
25:
26: //针对不同业务,加入新的客户到对应队列
27: public String generateTicket(BusinessType businessType){
28: switch(businessType){
29: case GENERAL:
30: return generalQueue.generateNewCustomer();
31: case QUICK:
32: return quickQueue.generateNewCustomer();
33: case VIP:
34: return vipQueue.generateNewCustomer();
35: }
36: return null;
37: }
38: //单例实现
39: private TicketMachine(){}
40: private static TicketMachine machineInstance = new TicketMachine();
41: public static TicketMachine getInstance(){
42: return machineInstance;
43: }
44: }
业务窗口Windows类:
1: /**
2: * 业务窗口
3: * @author Shawn
4: *
5: */
6: public class Windows {
7: private BusinessType businessType;//窗口业务类型
8: private int winNum;//窗口编号
9: private boolean available = false;//窗口开放状态
10:
11: public Windows(BusinessType businessType,int winNum) {
12: super();
13: this.businessType = businessType;
14: this.winNum = winNum;
15: }
16:
17: //开始业务
18: public void start(){
19: available = true;
20: System.out.println(this+"开始服务!");
21:
22: //创建新的线程开始不同窗口的业务
23: ExecutorService pool = Executors.newSingleThreadExecutor();
24: pool.execute(new Runnable(){
25: public void run(){
26: switch(businessType){
27: case GENERAL:
28: while(available){
29: generalService();
30: }
31: case QUICK:
32: while(available){
33: quickService();
34: }
35: case VIP:
36: while(available){
37: vipService();
38: }
39: }
40: }
41: });
42: }
43: //普通业务窗口服务过程
44: private void generalService(){
45: //普通业务只需要获得普通用户队列
46: Queue queue = TicketMachine.getInstance().getQueue(BusinessType.GENERAL);
47: //如果队列不为空,则开始叫号并模拟服务
48: if(!queue.isEmpty()){
49: String name = queue.getCustomer();
50: System.out.println(this+"正在为 "+name+"服务~");
51: int time = generalCustomerServicing();
52: //System.out.println(this+"服务完毕,耗时"+time+"秒");
53: }
54: else{
55: //System.out.println(this+"正在等待客户...");
56: try {
57: Thread.sleep(1000);
58: } catch (InterruptedException e) {
59: // TODO Auto-generated catch block
60: e.printStackTrace();
61: }
62: }
63: }
64: //快速窗口业务服务过程
65: private void quickService(){
66: //快速窗口需要得到快速队列以及普通队列
67: Queue quickQueue = TicketMachine.getInstance().getQueue(BusinessType.QUICK);
68: Queue generalQueue = TicketMachine.getInstance().getQueue(BusinessType.GENERAL);
69:
70: //首先判断快速队列
71: if(!quickQueue.isEmpty()){
72: String name = quickQueue.getCustomer();
73: System.out.println(this+"正在为 "+name+"服务~");
74: int time = quickCustomerServicing();
75: //System.out.println(this+"服务完毕,耗时"+time+"秒");
76: }
77: //若快速队列没有等待客户,则考虑普通队列
78: else if(!generalQueue.isEmpty()){
79: String name = generalQueue.getCustomer();
80: System.out.println(this+"正在为 "+name+"服务~");
81: int time = generalCustomerServicing();
82: //System.out.println(this+"服务完毕,耗时"+time+"秒");
83: }
84: else{
85: //System.out.println(this+"正在等待客户...");
86: try {
87: Thread.sleep(1000);
88: } catch (InterruptedException e) {
89: // TODO Auto-generated catch block
90: e.printStackTrace();
91: }
92: }
93: }
94: //vip窗口业务服务过程
95: private void vipService(){
96: //vip窗口需要得到的vip队列以及普通队列
97: Queue vipQueue = TicketMachine.getInstance().getQueue(BusinessType.VIP);
98: Queue generalQueue = TicketMachine.getInstance().getQueue(BusinessType.GENERAL);
99:
100: //如果vip队列不为空,则取出vip客户处理
101: if(!vipQueue.isEmpty()){
102: String name = vipQueue.getCustomer();
103: System.out.println(this+"正在为 "+name+"服务~");
104: int time = vipCustomerServicing();
105: //System.out.println(this+"服务完毕,耗时"+time+"秒");
106: }
107: //若vip队列为空,则考虑普通队列
108: else if(!generalQueue.isEmpty()){
109: String name = generalQueue.getCustomer();
110: System.out.println(this+"正在为 "+name+"服务~");
111: int time = generalCustomerServicing();
112: //System.out.println(this+"服务完毕,耗时"+time+"秒");
113: }
114: else{
115: //System.out.println(this+"正在等待客户...");
116: try {
117: Thread.sleep(1000);
118: } catch (InterruptedException e) {
119: // TODO Auto-generated catch block
120: e.printStackTrace();
121: }
122: }
123:
124: }
125: //服务普通客户的模拟时间
126: private int generalCustomerServicing(){
127: int time = new Random().nextInt(
128: Constants.MAX_SERVICE_TIME-Constants.MIN_SERVICE_TIME)+
129: Constants.MIN_SERVICE_TIME;
130: try {
131: Thread.sleep(time*1000);
132: } catch (InterruptedException e) {
133: // TODO Auto-generated catch block
134: e.printStackTrace();
135: }
136: return time;
137: }
138: //服务快速客户的模拟时间
139: private int quickCustomerServicing(){
140: int time = Constants.MIN_SERVICE_TIME;
141: try {
142: Thread.sleep(time*1000);
143: } catch (InterruptedException e) {
144: // TODO Auto-generated catch block
145: e.printStackTrace();
146: }
147: return time;
148: }
149: //服务vip客户的模拟时间
150: private int vipCustomerServicing(){
151: int time = new Random().nextInt(
152: Constants.MAX_SERVICE_TIME-Constants.MIN_SERVICE_TIME)+
153: Constants.MIN_SERVICE_TIME;
154: try {
155: Thread.sleep(time*1000);
156: } catch (InterruptedException e) {
157: // TODO Auto-generated catch block
158: e.printStackTrace();
159: }
160: return time;
161: }
162:
163: @Override
164: public String toString() {
165: // TODO Auto-generated method stub
166: return businessType+"窗口"+winNum+"号";
167: }
168: }
1: /**
2: * 统一维护的常量信息
3: * @author Shawn
4: *
5: */
6: public class Constants {
7:
8: //客户服务的最大时间 10s
9: public static int MAX_SERVICE_TIME = 10;
10: //客户服务的最小时间 5s
11: public static int MIN_SERVICE_TIME = 5;
12:
13: //产生普通客户的间隔时间 1s
14: public static int COMMON_ITTERVAL_TIME = 1;
15: }
1: public class MainClass {
2:
3: /**
4: * 测试代码
5: * @param args
6: */
7: public static void main(String[] args) {
8: ScheduledExecutorService timer = null;
9:
10: //建立普通窗口
11: for(int i = 1 ; i <= 4 ; i ++){
12: new Windows(BusinessType.GENERAL,i).start();
13: }
14: //建立快速窗口
15: new Windows(BusinessType.QUICK,1).start();
16: //建立VIP窗口
17: new Windows(BusinessType.VIP,1).start();
18: //普通用户拿票
19: timer = Executors.newScheduledThreadPool(1);
20: timer.scheduleAtFixedRate(
21: new Runnable(){
22: public void run(){
23: String name = TicketMachine.getInstance().generateTicket(BusinessType.GENERAL);
24: //System.out.println(name + "正在等待服务...");
25: }
26: },
27: 1,
28: Constants.COMMON_ITTERVAL_TIME,
29: TimeUnit.SECONDS);
30: //快速用户拿票
31: timer = Executors.newScheduledThreadPool(1);
32: timer.scheduleAtFixedRate(
33: new Runnable(){
34: public void run(){
35: String name = TicketMachine.getInstance().generateTicket(BusinessType.QUICK);
36: //System.out.println(name + "正在等待服务...");
37: }
38: },
39: 1,
40: Constants.COMMON_ITTERVAL_TIME*2,
41: TimeUnit.SECONDS);
42:
43: //普通用户拿票
44: timer = Executors.newScheduledThreadPool(1);
45: timer.scheduleAtFixedRate(
46: new Runnable(){
47: public void run(){
48: String name = TicketMachine.getInstance().generateTicket(BusinessType.VIP);
49: //System.out.println(name + "正在等待服务...");
50: }
51: },
52: 1,
53: Constants.COMMON_ITTERVAL_TIME*6,
54: TimeUnit.SECONDS);
55: }
56: }
总结
基本实现了银行取号调度的系统逻辑
在程序扩展性上产生了比较多的思考和疑惑,抓紧时间摸索设计模式,希望今后可以写出精良的代码