黑马程序员--银行业务调度系统

------------------ android培训java培训、期待与您交流! ---------------------

一、需求分析

1、银行有三种服务窗口:4个普通窗口,1VIP窗口,1个快速窗口。

2、普通窗口只为普通客户服务。

3、VIP窗口优先为VIP客户服务,如果没有VIP客户就为普通客户服务。快速窗口为快速客户(办理交水电费等)服务,如果没有快速客户就为普通客户服务。

4、异步随机生成客户,且普通客户,VIP客户,快速客户的比例是:6:1:3

5、服务顺序按照号码排序,不同用户按照不同服务类型取不同的号码,每种号码都按先后顺序排队,先来先享受服务。

6、窗口按照顺序叫号。

二、面向对象的分析与设计

1、对象:

(1)号码管理器,三种不同的客户,三种不同的号码表示。

(2)号码产生器,一个号码产生器能产生不同的号码,单例设计模式。

(3)服务窗口,能够生成不同服务窗口。

2、设计图:


3、号码管理器NumberManager

   能够生成客户号码,每来一个客户,就生成相应类型的号码,并把号码按顺序添加到集合中,generateNewNumber()方法。服务窗口能获取当前正在排队的号码,并且叫号之后,将该号码删除,fetchNumber()方法,如果没有客户则返回null

4、号码产生器NumberMachine

   相当于银行里那个产生号码的机器。只有一台,所以使用单例设计模式。号码产生器能根据需求产生三种不同的号码。所以需要有三个NumberManager的对象,分别产生不同的客户类型号码。

5、服务窗口ServiceWindow

   首先要设置自己的窗口类型type。如果是普通窗口,就叫普通号,有客户就服务,没有客户就休息一会再叫普通号。如果是VIP窗口,就叫VIP客户,有就服务,没有VIP客户就叫普通客户的号。快速窗口与VIP窗口同理,先叫快速客户,有就为快速客户服务,没有快速客户就叫普通客户的号,为普通客户服务。服务的过程通过相应NumberManager实例的fetchNumber()方法获取当前正在等待的客户号。可以使用Thread.sleep()方法模拟服务时间。使用while循环使服务窗口不停的执行命令,服务客户。

四、代码实现:

1、号码管理器NumberManager

import java.util.ArrayList;
import java.util.List;
public class NumberManager {
	private int lastNumber = 0;
	private List<Integer> numberQuene = new ArrayList<Integer>();//面向接口编程
	//生成号码,并添加到队列中等待
	//返回值最好写成Integer,以防null的出现
	public synchronized Integer generateNewNumber(){
		numberQuene.add(++lastNumber);
		return lastNumber;
	}
	public synchronized Integer fetchNumber(){
		//如果一个客户都没有,集合为空,则返回null,所以函数类型应使用Integer而不是int
		if(numberQuene.size()>0){
		return numberQuene.remove(0);
		}else{
			return null;
		}
		
	}
}

2、号码产生器NumberMachine

/**
 * 能生成三种号码,所以要有三个号码管理器NumberManager对象
 * */
public class NumberMachine {
	private NumberManager commonManager = new NumberManager();
	private NumberManager VIPManager = new NumberManager();
	private NumberManager ExpressManager = new NumberManager();
	public NumberManager getCommonManager() {
		return commonManager;
	}
	public NumberManager getVIPManager() {
		return VIPManager;
	}
	public NumberManager getExpressManager() {
		return ExpressManager;
	}
	//单例设计模式,饿汉式
	private static NumberMachine instance = new NumberMachine();
	private NumberMachine(){}
	public static NumberMachine getInstance(){
		return instance;
	}
}

3、服务窗口ServiceWindow

import java.util.Random;
import java.util.concurrent.Executors;
public class ServiceWindow {
	//这里需要一个默认的值吗,不一定,可以设置默认为普通,也可在生成窗口时再设置
	private CustomerType type;
	//number 为了方便表示第几个普通窗口,默认设置为1,这样VIP和快速窗口就不用设置了
	private int number = 1; 
	//便于生成服务窗口时设置窗口类型
	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无限循环,使其不停得执行命令,其实更高效做法是将while放在case下面,为了好看才如此
				while(true){//switch比if else的效率为什么高,switch的类型可以有哪些?枚举反正是可以的
					switch(type){
						case COMMON:
							commonService();
							break;
						case EXPRESS:
							ExpressService();
							break;
						case VIP:
							VIPService();
							break;
					}
				
				}
			}
		});
	}
	private void commonService() {
		String windowName = number+"号"+type+"窗口";//该服务窗口的名字
		System.out.println(windowName+"正在获取普通任务");
		//按顺序获取正在等待的第一个客户的号码
		Integer serviceNumber = NumberMachine.getInstance().getCommonManager().fetchNumber();
		if(serviceNumber != null){
			System.out.println(windowName+"正在为"+serviceNumber+"号普通客户服务");
			//设置普通客户服务时间为一个范围,且服务时间在该范围内随机
			int maxRadom = Constants.MAX_SERVICE_TIME - Constants.MIN_SERVICE_TIME;
			int serviceTime = new Random().nextInt(maxRadom)+Constants.MIN_SERVICE_TIME;
			try {
				//用线程休眠时间代表服务时间
				Thread.sleep(serviceTime);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.println(windowName+"为"+serviceNumber+"号普通客户服务完毕!");
		}else{
			System.out.println(windowName+"没有取到普通任务,休息1秒钟");
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	private void ExpressService() {
		String windowName = number+"号"+type+"窗口";
		System.out.println(windowName+"正在获取快速--任务");
		Integer serviceNumber = NumberMachine.getInstance().getExpressManager().fetchNumber();
		if(serviceNumber != null){
			System.out.println(windowName+"正在为"+serviceNumber+"号快速客户服务");
			try {
				Thread.sleep(Constants.MIN_SERVICE_TIME);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.println(windowName+"为"+serviceNumber+"号快速客户服务完毕!");
		}else{
			System.out.println(windowName+"没有取到快速任务,去获取普通客户任务");
			commonService();
		}
	}
	private void VIPService() {
		String windowName = number+"号"+type+"窗口";
		System.out.println(windowName+"正在获取VIP任务");
		Integer serviceNumber = NumberMachine.getInstance().getVIPManager().fetchNumber();
		if(serviceNumber != null){
			System.out.println(windowName+"正在为"+serviceNumber+"号VIP客户服务");
			int maxRadom = Constants.MAX_SERVICE_TIME - Constants.MIN_SERVICE_TIME;
			int serviceTime = new Random().nextInt(maxRadom)+Constants.MIN_SERVICE_TIME;
			try {
				Thread.sleep(serviceTime);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.println(windowName+"为"+serviceNumber+"号VIP客户服务完毕!");
		}else{
			System.out.println(windowName+"没有取到VIP任务,去获取普通客户任务");
			commonService();
		}
	}
}

4、测试类BankTest

import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class BankTest {
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		//产生四个普通窗口
		for(int i = 1;i<5;i++){
			ServiceWindow commonWindow = new ServiceWindow();
			commonWindow.setNumber(i);
			commonWindow.setType(CustomerType.COMMON);
			commonWindow.start();
		}
		//生成一个VIP窗口
		ServiceWindow VIPWindow = new ServiceWindow();
		VIPWindow.setType(CustomerType.VIP);
		VIPWindow.start();
		//生成一个快速窗口
		ServiceWindow ExpressWindow = new ServiceWindow();
		ExpressWindow.setType(CustomerType.EXPRESS);
		ExpressWindow.start();
		//普通客户拿号码
		Executors.newScheduledThreadPool(1).scheduleAtFixedRate(new Runnable(){
			@Override
			public void run() {
				Integer commonServiceNumber = NumberMachine.getInstance().getCommonManager().generateNewNumber();
				System.out.println("第个"+commonServiceNumber+"普通客户正在等待服务");
			}},
				0, 
				Constants.COMMON_CUSTOMER_INTERVAL_TIME,
				TimeUnit.SECONDS);
	
		//VIP客户取号码
		Executors.newScheduledThreadPool(1).scheduleAtFixedRate(new Runnable(){

			@Override
			public void run() {
				Integer VIPServiceNumber = NumberMachine.getInstance().getVIPManager().generateNewNumber();
				System.out.println("第个"+VIPServiceNumber+"VIP客户正在等待服务");
			}},
				0, 
				Constants.COMMON_CUSTOMER_INTERVAL_TIME*6,
				TimeUnit.SECONDS);
		//快速客户取号码
		Executors.newScheduledThreadPool(1).scheduleAtFixedRate(new Runnable(){
			@Override
			public void run() {
				Integer ExpressServiceNumber = NumberMachine.getInstance().getExpressManager().generateNewNumber();
				System.out.println("第个"+ExpressServiceNumber+"快速客户正在等待服务");
			}},
				0, 
				Constants.COMMON_CUSTOMER_INTERVAL_TIME*2,
				TimeUnit.SECONDS);
	}
}

5、提取的静态变量:

public class Constants {
	public static int MAX_SERVICE_TIME = 10000;//10秒,因为sleep单位是ms
	public static int MIN_SERVICE_TIME = 1000;//1秒,因为sleep单位是ms
	public static int COMMON_CUSTOMER_INTERVAL_TIME = 1;//用于每一秒产生一个普通客户
}

6、客户类型枚举:

public enum CustomerType {
	COMMON,VIP,EXPRESS;
	//复写toString方法,当打印类型名时,COMMON打印出“普通”等,更加友好
	public String toString(){
		String name = null;
		switch(this){
			case COMMON:
				name = "普通";
				break;
			case VIP:
				name = "VIP";
				break;
			case EXPRESS:
				name = "快速";
				break;
		}
		return name;
	}
}

五、小知识点总结:

1if …else 为什么比switch…case效率低

   这是因为if…else每次都要从头遍历查询,直到命中。而switch…case是生成跳转表,根据跳转表,直接跳转到符合条件的语句,减少了遍历次数,所以效率高。

2、面试题:switch(option)…caseoption的类型可以有哪些?

可以是intshortbytechar和枚举类型的。 



Java编写银行业务调度系统,附主类: package com.isoftstons.interview.bank; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; public class Mainlass { public Mainlass() { } public static void main(String[] args) { ServiceWindow vipWindow; for(int i = 1; i < 5; ++i) { vipWindow = new ServiceWindow(); vipWindow.setWindowId(i); vipWindow.start(); } ServiceWindow expressWindow = new ServiceWindow(); expressWindow.setType(CustomerType.EXPRESS); expressWindow.start(); vipWindow = new ServiceWindow(); vipWindow.setType(CustomerType.VIP); vipWindow.start(); Executors.newScheduledThreadPool(1).scheduleAtFixedRate(new Runnable() { public void run() { Integer number = NumberMachine.getInstance().getCommonManager().generateNewManager(); System.out.println(number + "号普通客户等待服务"); } }, 0L, (long)Constants.COMMON_CUSTOMER_INTERVAL_TIME, TimeUnit.SECONDS); Executors.newScheduledThreadPool(1).scheduleAtFixedRate(new Runnable() { public void run() { Integer number = NumberMachine.getInstance().getExpressManager().generateNewManager(); System.out.println(number + "号快速客户等待服务"); } }, 0L, (long)(Constants.COMMON_CUSTOMER_INTERVAL_TIME * 6), TimeUnit.SECONDS); Executors.newScheduledThreadPool(1).scheduleAtFixedRate(new Runnable() { public void run() { Integer number = NumberMachine.getInstance().getVipManager().generateNewManager(); System.out.println(number + "号VIP客户等待服务"); } }, 0L, (long)(Constants.COMMON_CUSTOMER_INTERVAL_TIME * 2), TimeUnit.SECONDS); } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值