银行业务调度系统

今天在网上看到一道关于银行业务调度系统的题目,感觉有点意思,就动手写了写代码,记录一下。


题目:


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

}

到此,这个题目就算完全做完了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值