题目:
模拟实现银行业务调度系统逻辑,具体需求如下:
*银行内有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(); }
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); }
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; }
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; } }
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; }
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; }
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); } }