银行业务调度系统


银行业务调度系统

一、问题描述


模拟实现银行业务调度系统逻辑,具体需求如下:

   1.银行内有6个业务窗口,1 - 4号窗口为普通窗口,5号窗口为快速窗口,6号窗口为VIP窗口。

   2.有三种对应类型的客户:VIP客户,普通客户,快速客户(办理如交水电费、电话费之类业务的客户)。

   3.异步随机生成各种类型的客户,生成各类型用户的概率比例为:

       VIP客户:普通客户 :快速客户 = 16 3

   4.客户办理业务所需时间有最大值和最小值,在该范围内随机设定每个VIP客户以及普通客户办理业务所需的时间,快速客户办理业务所需时间为最小值(提示:办理业务的过程可通过线程Sleep的方式模拟)。

   5.各类型客户在其对应窗口按顺序依次办理业务。

   6.VIP6号)窗口和快速业务(5号)窗口没有客户等待办理业务的时候,这两个窗口可以处理普通客户的业务,而一旦有对应的客户等待办理业务的时候,则优先处理对应客户的业务。

   7.随机生成客户时间间隔以及业务办理时间最大值和最小值自定,可以设置。

   8.不要求实现GUI,只考虑系统逻辑实现,可通过Log方式展现程序运行结果。


二、问题分析


1.有三种对应类型的客户:VIP客户,普通客户,快速客户 ,异步随机生成各种类型的客户,各类型客户在其对应窗口按顺序依次办理业务。

1)首先,经常在银行办理业务的人更有利于理解本系统,所以想到要有一个号码管理器对象,让这个对象不断地产生号码,就等于随机生成了客户。

2)由于有三类客户,每类客户的号码编排都是完全独立的,所以,我想到本系统一共要产生三个号码管理器对象,各自管理一类用户的排队号码。这三个号码管理器对象统一由一个号码机器进行管理,这个号码机器在整个系统中始终只能有一个,所以,它要被设计成单例。

2.各类型客户在其对应窗口按顺序依次办理业务 ,准确地说,应该是窗口依次叫号。

各个窗口怎么知道该叫哪一个号了呢?它一定是问的相应的号码管理器,即服务窗口每次找号码管理器获取当前要被服务的号码。


三、代码实现


首先根据问题的分析画图理解:



1.NumberManager

1)定义一个用于存储上一个客户号码的成员变量和用于存储所有等待服务的客户号码的队列集合。

2)定义一个产生新号码的方法和获取马上要为之服务的号码的方法,这两个方法被不同的线程操作了相同的数据,所以,要进行同步。

public class NumberManger {
	private int lastNumber = 0;//上一个客户号码
	//存储所有等待服务的客户号码队列
	private List<Integer> queueNumbers = new ArrayList<Integer>();
	
	//产生新号码
	public synchronized Integer generateNewNumber(){
		queueNumbers.add(++lastNumber);//产生的号码添加到集合中
		return lastNumber;
	}
	
	//获取要为服务的号码
	public synchronized Integer fetchNumber(){
		if(queueNumbers.size()>0){
			return queueNumbers.remove(0);//从集合中取出第一个
		}else
			return null;
	}
}



2.NumberMachine

1)定义三个成员变量分别指向三个NumberManager对象,分别表示普通、快速和VIP客户的号码管理器,定义三个对应的方法来返回这三个NumberManager对象。

2)将NumberMachine类设计成单例。

public class NumberMachine {
	//将NumberMachine设计成饱汉式单例
	private NumberMachine(){}//构造函数私有
	//创建本类对象
	private static NumberMachine machine = new NumberMachine();
	//对外提供一个静态方法可以获取到该类的对象
	public static NumberMachine getInstance(){
		return machine;
	}
	
	//产生三个Manger对象,分别是普通、快速和Vip
	private NumberManger commonManger = new NumberManger();
	private NumberManger expressManger = new NumberManger();
	private NumberManger vipManger = new NumberManger();
	
	//定义方法来返回CommonManger对象
	public NumberManger getCommonManger(){
		return commonManger;
	}
	//定义方法来返回ExpressManger对象
	public NumberManger getExpressManger(){
		return expressManger;
	}
	//定义方法来返回VipManger对象
	public NumberManger getVipManger(){
		return vipManger;
	}
}


3.CustomerType枚举类

1)系统中有三种类型的客户,所以用定义一个枚举类,其中定义三个成员分别表示三种类型的客户。

2)重写toString方法,返回类型的中文名称。这是在后面编码时重构出来的,刚开始不用考虑。

//只有三类客户所以定义成枚举类
public enum CustomerType {
	//表示三种类型的客户
	COMMON,EXPRESS,VIP;
	
	//重写toString方法,返回枚举类型的中文名称
	@Override
	public String toString() {
		String name = null;
		switch(this){
		case COMMON:
			name = "普通";
			break;
		case EXPRESS:
			name = "快速";
			break;
		case VIP:
			name = name();
			break;
		}
		return name;
	}
	
}


4.ServiceWindow

1)定义一个start方法,内部启动一个线程,根据服务窗口的类别分别循环调用三个不同的方法。

2)定义三个方法分别对三种客户进行服务,为了观察运行效果,应详细打印出其中的细节信息。

//服务窗口类
public class ServiceWindow {
	private CustomerType type = CustomerType.COMMON;//客户类别
	private int number;//哪个窗口服务
	
	public CustomerType getType(){
		return type;
	}
	//设置客户类别
	public void setType(CustomerType type){
		this.type = type;
	}
	//设置窗口
	public void setNumber(int number){
		this.number = number;
	}
	
	//在内部启动一个线程,并根据服务窗口的类别分别判断调用哪个方法
	public void start(){
		Executors.newSingleThreadExecutor().execute(new Runnable() {
			
			@Override
			public void run() {
				while(true){
					switch(type){
					case COMMON:
						commonService();//调用普通服务
						break;
					case EXPRESS:
						expressService();//调用快速服务
						break;
					case VIP:
						vipService();//调用vip服务
						break;
					}
				}
				
			}
		});
	}
	//普通服务
	private void commonService() {
		String windowName = "第"+number+"号"+type+"窗口";
		System.out.println(windowName + "正在获取任务...");
		//普通服务取到号
		Integer serviceNumber = NumberMachine.getInstance().getCommonManger().fetchNumber();
		//如果取到号了,就处理普通客户
		if(serviceNumber != null){
			System.out.println(windowName+"正在为第"+serviceNumber+"个普通客户服务");
			int maxRandom = Constants.MAX_SERVICE_TIME - Constants.MIN_SERVICE_TIME;
			long beginTime = System.currentTimeMillis();
			//产生1-10000的随机数
			int serviceTime = new Random().nextInt(maxRandom)+1+Constants.MIN_SERVICE_TIME;
			try {
				Thread.sleep(serviceTime);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			long costTime = System.currentTimeMillis() - beginTime;
			System.out.println(windowName+"为第"+serviceNumber+"个"+"普通"+"客户完成,耗时"+costTime/1000+"秒");
		}else{
			//如果没取到号,则打印窗口没有取到号
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.println(windowName+"没有取到号");
		}
	}
	
	//快速服务
	private void expressService() {
		String windowName = "第"+number+"号"+type+"窗口";
				System.out.println(windowName+"正在获取任务...");
				//快速服务取号
				Integer serviceNumber = NumberMachine.getInstance().getExpressManger().fetchNumber();
				//取到号了就处理快速服务
				if(serviceNumber != null){
					System.out.println(windowName+"正在为第"+serviceNumber+"个"+type+"客户服务");
					long beginTime = System.currentTimeMillis();
					try {
						Thread.sleep(Constants.MIN_SERVICE_TIME);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					long costTime = System.currentTimeMillis() - beginTime;
					System.out.println(windowName+"为第"+serviceNumber+"个"+type+"客户完成,耗时"+costTime/1000+"秒");
				}else{
					commonService();//如果没有取到快速客户,则为普通窗口服务
				}
		
	}
	
	//vip服务
	private void vipService() {
		String windowName = "第"+number+"号"+type+"窗口";
		System.out.println(windowName + "正在获取任务...");
		//vip服务取号
		Integer serviceNumber = NumberMachine.getInstance().getVipManger().fetchNumber();
		//如果取到vip服务了,则进行vip客户服务
		if(serviceNumber != null){
			System.out.println(windowName+"正在为第"+serviceNumber+"个"+type+"客户服务");
			long beginTime = System.currentTimeMillis();
			try {
				Thread.sleep(Constants.MIN_SERVICE_TIME);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			long costTime = System.currentTimeMillis()- beginTime;
			System.out.println(windowName+"为第"+serviceNumber+"个"+type+"客户完成,耗时"+costTime/1000+"秒");
		}
		else{
			commonService();//如果没有取到vip客户,则进行普通客户服务
		}
		
	}
}

5.Constants

定义两个常量:MAX_SERVICE_TIMEMIN_SERVICE_TIME

//常量类
public class Constants {
	//最大服务时间
	public static final int MAX_SERVICE_TIME = 10000;
	//最短服务时间
	public static final int MIN_SERVICE_TIME = 1000;
}


6.测试类

1)用for循环创建出4个普通窗口,再创建出1个快速窗口和一个VIP窗口。

2)接着再创建三个定时器,分别定时去创建新的普通客户号码、新的快速客户号码、新的VIP客户号码。

public class Test {

	public static void main(String[] args) {
		//4个普通窗口
		for (int i = 0; i < 5; i++) {
			ServiceWindow commonWindow = new ServiceWindow();
			commonWindow.setNumber(i);//设置服务窗口号
			commonWindow.start();//开始服务
		}
		//1个快速窗口
		ServiceWindow expreWindow = new ServiceWindow();
		expreWindow.setType(CustomerType.EXPRESS);//设置服务类别为快速客户
		expreWindow.start();
		//1个vip窗口
		ServiceWindow vipWindow = new ServiceWindow();
		vipWindow.setType(CustomerType.VIP);//设置服务类别为vip客户
		vipWindow.start();
		
		//开启线程执行普通服务
		Executors.newScheduledThreadPool(1).scheduleAtFixedRate(new Runnable() {
			
			@Override
			public void run() {
				// TODO Auto-generated method stub
				Integer number = NumberMachine.getInstance().getCommonManger().generateNewNumber();
				System.out.println(number+"号普通客户等待服务");
			}
		},
		0,
		1,//每隔1秒出现一个普通客户
		TimeUnit.SECONDS);
		
		//开启线程执行快速服务
		Executors.newScheduledThreadPool(1).scheduleAtFixedRate(new Runnable() {
			
			@Override
			public void run() {
				Integer serviceNumber = NumberMachine.getInstance().getExpressManger().generateNewNumber();
				System.out.println(serviceNumber+"号快速客户等待服务");
			}
		}, 
		0, 
		2, //每隔2秒出现一个vip客户
		TimeUnit.SECONDS);

		//开启线程执行vip服务
		Executors.newScheduledThreadPool(1).scheduleAtFixedRate(new Runnable() {
			
			@Override
			public void run() {
				Integer serviceNumber = NumberMachine.getInstance().getVipManger().generateNewNumber();
				System.out.println(serviceNumber+"号快vip户等待服务");
				
			}
		}, 
		0, 
		6, //每隔1秒出现一个vip客户
		TimeUnit.SECONDS);
	}

}

部分运行结果:


第2号普通窗口正在获取任务...
第2号普通窗口正在为第10个普通客户服务
第0号普通窗口没有取到号
第0号普通窗口正在获取任务...
第0号VIP窗口为第6个普通客户完成,耗时4秒
第0号VIP窗口正在获取任务...
第0号VIP窗口正在为第2个VIP客户服务
11号普通客户等待服务
6号快速客户等待服务
第0号普通窗口没有取到号
第0号普通窗口正在获取任务...
第0号普通窗口正在为第11个普通客户服务
第0号VIP窗口为第2个VIP客户完成,耗时1秒
第0号VIP窗口正在获取任务...
第0号VIP窗口正在获取任务...
12号普通客户等待服务
第0号VIP窗口没有取到号
第0号VIP窗口正在获取任务...
第0号VIP窗口正在获取任务...
第0号VIP窗口正在为第12个普通客户服务
第0号普通窗口为第11个普通客户完成,耗时1秒
第0号普通窗口正在获取任务...
7号快速客户等待服务
13号普通客户等待服务
3号快vip户等待服务
第0号快速窗口为第8个普通客户完成,耗时5秒
第0号快速窗口正在获取任务...
第0号快速窗口正在为第5个快速客户服务
第1号普通窗口为第9个普通客户完成,耗时4秒
第1号普通窗口正在获取任务...

...

可以看到VIP窗口既为VIP客户服务也为普通用户服务,快速窗口既为快速客户服务也为普通客户服务,而普通窗口只能为普通窗口服务。基本符合要求。





  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值