------- android培训、java培训、期待与您交流! ----------
模拟实现银行业务调度系统逻辑,具体需求如下:
Ø 银行内有6个业务窗口,1 - 4号窗口为普通窗口,5号窗口为快速窗口,6号窗口为VIP窗口。
Ø 有三种对应类型的客户:VIP客户,普通客户,快速客户(办理如交水电费、电话费之类业务的客户)。
Ø 异步随机生成各种类型的客户,生成各类型用户的概率比例为: VIP客户 :普通客户 :快速客户 = 1 :6 :3。
Ø客户办理业务所需时间有最大值和最小值,在该范围内随机设定每个VIP客户以及普通客户办理业务所需的时间,快速客户办理业务所需时间为最小值(提示:办理业务的过程可通过线程Sleep的方式模拟)
Ø各类型客户在其对应窗口按顺序依次办理业务。
Ø当VIP(6号)窗口和快速业务(5号)窗口没有客户等待办理业务的时候,这两个窗口可以处理普通客户的业务,而一旦有对应的客户等待办理业务的时候,则优先处理对应客户的业务
Ø 随机生成客户时间间隔以及业务办理时间最大值和最小值自定,可以设置。
Ø 不要求实现GUI,只考虑系统逻辑实现,可通过Log方式展现程序运行结果。
根据上述需求,理下代码逻辑:
1、有三类不同客户,在银行都是有号码管理器对象设定编号,且三类客户编号互不干涉,为此需要三个号码管理器对象为对应的客户生产一个编号,放在队列中(先进先出); 且号码管理器都有一个号码机器进行管理,而号码机器在使用中只有一个,故需要有号码机器对象,并且是唯一的,所以要设计成单例
2、客户依次在服务窗口办业务,也就是服务窗口要依次叫号。也就是说服务窗口找相应的号码管理器对象获取当前被服务的号码。根据面向对象思想
获取当前被服务的号码的方法应在号码管理器对象中,服务窗口有个方法只要不断调用即可
那么就有了以下几个对象
1)队列:先进先出,存储客户编号和获取客户编号
package com.heima.bank;
import java.util.LinkedList;
/**
* 队列(先进先出)
* @author Administrator *
* @param <T>
*/
public class Quere<T> {
//存储客户编号
private LinkedList<T> list = null;
public Quere(){
list = new LinkedList<>();
}
/**
* 添加元素
* @param t 元素
*/
public void addNumber(T t){
list.addFirst(t);
}
/**
* 获取元素
* @return 返回元素
*/
public T getNumber(){
return list.removeLast();
}
/**
* 判断队列是否为空
* @return true,表示空;false,表示不空
*/
public boolean isEmpty(){
return list.isEmpty();
}
}
2)号码管理器对象:管理生产号码和获取号码,这里多线程操作相同数据,故需要同步
package com.heima.bank;
/**
* 号码管理器
* @author Administrator
*
*/
public class NumberManger {
private int number = 1;
private Quere<Integer> quere = null;
public NumberManger(){
quere = new Quere<Integer>();
}
/**
* 生成客戶编号,自动存储队列中
* @return 客户编号
*/
public synchronized int getNumber(){
quere.addNumber(number);
return number++;
}
/**
* 服务窗口叫号,自动从队列中获取
* @return 客户编号
*/
public synchronized Integer callNumber(){
if(!quere.isEmpty())
return quere.getNumber();
else
return null;
}
}
3)号码机器对象 : 管理三个号码管理器对象,为三个不同类型的客户生产号码,且只有一个对象,所以需要使用单例模式
package com.heima.bank;
/**
* 号码机器,主要管理号码管理器
* @author Administrator
*
*/
public class NumberMachine {
//普通客户号码管理器
private NumberManger comNumberManger =new NumberManger();
//快速客户号码管理器
private NumberManger expressNumberManger =new NumberManger();
//VIP客户号码管理器
private NumberManger vipNumberManger =new NumberManger();
public NumberManger getComNumberManger() {
return comNumberManger;
}
public NumberManger getExpressNumberManger() {
return expressNumberManger;
}
public NumberManger getVipNumberManger() {
return vipNumberManger;
}
//单例模式创建对象
private static NumberMachine instance = new NumberMachine();
private NumberMachine(){}
public static NumberMachine getInstance(){
return instance;
}
}
4)枚举 : 管理三个不同类型的客户,普通、快速、VIP
package com.heima.bank;
/**
* 客戶類型(普通、快速、VIP)
* @author Administrator
*
*/
public enum CustormType {
COM,EXPRESS,VIP;
//返回对应的文本
public String toString(){
switch (this) {
case COM:
return "普通";
case EXPRESS:
return "快速";
case VIP:
return "VIP";
}
return null;
}
}
5)服务窗口对象:这个有三种类型的服务,且都有个服务客户的方法,且每个类型的客户所服务的内容不一样,为此可以设计一个抽象父类,父类中有个
抽象方法(服务客户的方法),三种类型的服务窗口对应着三个子类,继承抽象父类,重写抽象方法
package com.heima.bank;
import java.util.Random;
import java.util.concurrent.Executors;
/**
* 叫号窗口
* @author Administrator
*
*/
public abstract class ServiceWindow {
//服务窗口编号
private int windowId =1;
//客户类型
private CustormType type ;
public void setType(CustormType type) {
this.type = type;
}
public ServiceWindow( ){
}
public void setWindowId(int windowId) {
this.windowId = windowId;
}
public int getWindowId() {
return this.windowId;
}
/**
* 服务窗口开始工作
* @return
*/
public void startWork(){
Executors.newSingleThreadExecutor().execute(new Runnable() {
@Override
public void run() {
while(true){
service();
}
}
});
}
public abstract void service();
//为普通客户服务
public void comService() {
String windowName = windowId+"号"+type+"窗口";
System.out.println(windowName+"正在获取任务……");
Integer number = NumberMachine.getInstance().getComNumberManger().callNumber();
if(number!=null){
long start_time = System.currentTimeMillis();
System.out.println(windowName+"获取到任务,正在为"+number+"号普通客户服务");
int ser_time = Constion.MAXTIME - Constion.MINTIME;
ser_time = new Random().nextInt(ser_time)+1+Constion.MINTIME;
try {
Thread.sleep(ser_time);
} catch (InterruptedException e) {
e.printStackTrace();
}
long span_time = System.currentTimeMillis() - start_time;
System.out.println(windowName+"为"+number+"号普通客户服务结束,耗时"+(span_time)/1000+"秒");
}else{
System.out.println(windowName+"没有获取到任务,先休息一秒……");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
package com.heima.bank;
/**
* 普通服务窗口
* @author Administrator
*
*/
public class ComServiceWindow extends ServiceWindow {
@Override
public void service() {
super.comService();
}
}
package com.heima.bank;
/**
* 快速服务窗口
* @author Administrator
*
*/
public class ExpressServiceWindow extends ServiceWindow {
@Override
public void service() {
setType(CustormType.EXPRESS);
String windowName = getWindowId()+"号"+CustormType.EXPRESS+"窗口";
System.out.println(windowName+"正在获取任务……");
Integer number = NumberMachine.getInstance().getExpressNumberManger().callNumber();
if(number!=null){
long start_time = System.currentTimeMillis();
System.out.println(windowName+"获取到任务,正在为"+number+"号"+CustormType.EXPRESS+"客户服务");
int ser_time = Constion.MINTIME;
try {
Thread.sleep(ser_time);
} catch (InterruptedException e) {
e.printStackTrace();
}
long span_time = System.currentTimeMillis() - start_time;
System.out.println(windowName+"为"+number+"号"+CustormType.EXPRESS+"客户服务结束,耗时"+(span_time)/1000+"秒");
}else{
System.out.println(windowName+"没有获取到任务……");
super.comService();
}
}
}
package com.heima.bank;
import java.util.Random;
/**
* VIP服务窗口
* @author Administrator
*
*/
public class VIPServiceWindow extends ServiceWindow {
@Override
public void service() {
setType(CustormType.VIP);
String windowName = getWindowId()+"号"+CustormType.VIP+"窗口";
System.out.println(windowName+"正在获取任务……");
Integer number = NumberMachine.getInstance().getVipNumberManger().callNumber();
if(number!=null){
long start_time = System.currentTimeMillis();
System.out.println(windowName+"获取到任务,正在为"+number+"号"+CustormType.VIP+"客户服务");
int ser_time = Constion.MAXTIME - Constion.MINTIME;
ser_time = new Random().nextInt(ser_time)+1+Constion.MINTIME;
try {
Thread.sleep(ser_time);
} catch (InterruptedException e) {
e.printStackTrace();
}
long span_time = System.currentTimeMillis() - start_time;
System.out.println(windowName+"为"+number+"号"+CustormType.VIP+"客户服务结束,耗时"+(span_time)/1000+"秒");
}else{
System.out.println(windowName+"没有获取到任务……");
super.comService();
}
}
}
6)还有个主类,程序运行主口:创建4个普通的服务窗口各自叫号,创建快速窗口依次叫号,创建VIP窗口依次叫号;接着再创建三个定时器,依次创建普通客户、快速客户和VIP客户
package com.heima.bank;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class MainClass {
/**
* 银行调度主入口
* @param args
*/
public static void main(String[] args) {
//1到4窗口为普通窗口
for (int i = 1; i < 5; i++) {
ServiceWindow comService = new ComServiceWindow();
comService.setWindowId(i);
comService.startWork();
}
//这里是快速窗口服务
ServiceWindow expressService = new ExpressServiceWindow();
expressService.setWindowId(5);
expressService.startWork();
//这里是VIP窗口服务
ServiceWindow vipService = new VIPServiceWindow();
vipService.setWindowId(6);
vipService.startWork();
//定时每秒生产普通客户
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
new Runnable() {
@Override
public void run() {
Integer number= NumberMachine.getInstance().getComNumberManger().getNumber();
System.out.println("编号为"+number+"的普通客户等待服务……");
}
},
0,
1,
TimeUnit.SECONDS
);
//定时每2秒产生快速客户
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
new Runnable() {
@Override
public void run() {
Integer number= NumberMachine.getInstance().getExpressNumberManger().getNumber();
System.out.println("编号为"+number+"的快速客户等待服务……");
}
},
0,
2,
TimeUnit.SECONDS
);
//定时每6秒产生VIP客户
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
new Runnable() {
@Override
public void run() {
Integer number= NumberMachine.getInstance().getVipNumberManger().getNumber();
System.out.println("编号为"+number+"的VIP客户等待服务……");
}
},
0,
6,
TimeUnit.SECONDS
);
}
}
与视频不一样的地方在于,存储客户集合使用的是队列,需要依次叫号,先来先被服务,所谓先进先出;第二个是服务窗口抽取为抽象父类,里面有个抽象方法,只要子类实现该方法就可以。但还可以继续优化