【学习并改进】黑马程序员-张孝祥-银行业务调度系统

import java.util.*; //导入工具包
import java.util.concurrent.*; //导入并发包

/**
 * 产生多个窗口的叫号系统和模拟不同类型的客户操作。
 * 异步随机生成各种类型的客户,通过设定标准时间间隔倍数实现。
 * 有3种业务类型:普通用户,快速用户,VIP用户,
 * 各类型客户在对应窗口按顺序依次办理业务。
 * @author 张孝祥-黑马程序员
 * @editor 魏安-黑马程序员
 */
public class BankService //银行服务类
{
	public static void main(String[] Ann) //程序入口
	{
		CommonWindow(4); //执行普通窗口功能
		ExpressWindow(2); //执行快速窗口功能
		VIPWindow(1); //执行贵宾窗口功能
	}
	static void CommonWindow(int x) //普通窗口功能
	{
		/*产生普通窗口*/
		for (int i = 1; i <= x; i++) //循环次数
		{
			ServiceWindow window = new ServiceWindow(); //建立服务窗口对象
			window.setType(CustomerType.COMMON); //窗口对象设定类型
			window.setNumber(i); //服务窗口对象设定窗口数
			window.startService(); //服务窗口对象开启服务
		}
		/*普通客户拿号*/
		Runnable Common = new Runnable() //建立可运行多线程类对象为普通操作
		{
			@Override //系统覆写标记
			public void run() //覆写系统运行功能
			{
				Integer serviceNumber = CustomerManager.getInstance().getCommonCustomer().generateNewNumber(); //定义整数类型变量为服务号并得到客户经理类调用自身相应功能后执行同步生成新号码功能结果
				System.out.println("第" + serviceNumber + "号普通客户正在等待服务!"); //打印信息
			}
		}; //匿名内部类调用方式
		Executors.newScheduledThreadPool(1).scheduleAtFixedRate(Common,0,Constants.COMMON_CUSTOMER_INTERVAL_TIME,TimeUnit.SECONDS); //执行器创建安排线程池按照参数循环执行普通操作
	}
	static void ExpressWindow(int x) //快速窗口功能
	{
		/*产生快速窗口*/
		for (int i = 1; i <= x; i++) //循环次数
		{
			ServiceWindow expressWindow = new ServiceWindow(); //建立服务窗口对象
			expressWindow.setType(CustomerType.EXPRESS); //窗口对象设定类型
			expressWindow.setNumber(i); //服务窗口对象设定窗口数
			expressWindow.startService(); //服务窗口对象开启服务
		}
		/*快速客户拿号*/
		Runnable Express = new Runnable() //建立可运行多线程类对象为快速操作
		{
			@Override //系统覆写标记
			public void run() //覆写系统运行功能
			{
				Integer serviceNumber = CustomerManager.getInstance().getExpressCustomer().generateNewNumber(); //定义整数类型变量为服务号并得到客户经理类调用自身相应功能后执行同步生成新号码功能结果
				System.out.println("第" + serviceNumber + "号快速客户正在等待服务!"); //打印信息
			}
		}; //匿名内部类调用方式
		Executors.newScheduledThreadPool(1).scheduleAtFixedRate(Express,0,Constants.COMMON_CUSTOMER_INTERVAL_TIME * 2,TimeUnit.SECONDS); //执行器创建安排线程池按照参数循环执行快速操作
	}
	static void VIPWindow(int x) //贵宾窗口功能
	{
		/*产生贵宾窗口*/
		for (int i = 1; i <= x; i++) //循环次数
		{
			ServiceWindow vipWindow = new ServiceWindow(); //建立服务窗口对象
			vipWindow.setType(CustomerType.VIP); //窗口对象设定类型
			vipWindow.setNumber(i); //服务窗口对象设定窗口数
			vipWindow.startService(); //服务窗口对象开启服务
		}
		/*贵宾客户拿号*/
		Runnable VIP = new Runnable() //建立可运行多线程类对象为贵宾操作
		{
			@Override //系统覆写标记
			public void run() //覆写系统运行功能
			{
				Integer serviceNumber = CustomerManager.getInstance().getVIPCustomer().generateNewNumber(); //定义整数类型变量为服务号并得到客户经理类调用自身相应功能后执行同步生成新号码功能结果
				System.out.println("第" + serviceNumber + "号VIP客户正在等待服务!"); //打印信息
			}
		}; //匿名内部类调用方式
		Executors.newScheduledThreadPool(1).scheduleAtFixedRate(VIP,0,Constants.COMMON_CUSTOMER_INTERVAL_TIME * 6,TimeUnit.SECONDS); //执行器创建安排线程池按照参数循环执行贵宾操作
	}
}

/**
 * 定义一个枚举类,其中定义三个成员分别表示三种类型的客户。
 * 重写toString方法,返回类型的中文名称。
 * @author 张孝祥-黑马程序员
 * @editor 魏安-黑马程序员
 */
enum CustomerType //客户类型枚举
{
	COMMON,EXPRESS,VIP; //定义枚举元素
	@Override //系统覆写标记
	public String toString() //覆写系统文字功能
	{
		String name = null; //定义字符串变量为枚举元素名并初始化
		switch (this) //根据传入值选择以下分支
		{
			case COMMON: //选项对应值
				name = "普通"; //对应值为枚举元素名
				break; //选择结束
			case EXPRESS: //选项对应值
				name = "快速"; //对应值为枚举元素名
				break; //选择结束
			case VIP: //选项对应值
				name = name(); //对应值为枚举元素名
				break; //选择结束
		}
		return name; //返回枚举元素名
	}
}

/**
 * 定义常用的标准数值,以方便频繁调用。
 * 客户办理业务所需时间有最大最小值,定义标准时间间隔。
 * @author 张孝祥-黑马程序员
 * @editor 魏安-黑马程序员
 */
class Constants //常量字段值类
{
	public static int MAX_SERVICE_TIME = 10000; //定义整形数据变量为最大服务时间
	public static int MIN_SERVICE_TIME = 1000; //定义整形数据变量为最小服务时间
	public static int COMMON_CUSTOMER_INTERVAL_TIME = 1; //定义整形数据变量为产生标准客户时间
}

/**
 * 定义一个用于存储上一个客户号码的成员变量和用于存储所有等待服务的客户号码的队列集合。
 * 定义一个产生新号码的方法和获取马上要为之服务的号码的方法,这两个方法被不同的线程操作了相同的数据,所以要进行同步。
 * @author 张孝祥-黑马程序员
 * @editor 魏安-黑马程序员
 */
class NumberMachine //取号机类
{
	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 (Integer)queueNumbers.remove(0); //返回转换后容器移除首角标元素值
		}
		else //否则执行
		{
			return null; //返回空值
		}
	}
}

/**
 * 客户号码管理器,设计成单例。
 * @author 张孝祥-黑马程序员
 * @editor 魏安-黑马程序员
 */
class CustomerManager //客户经理类
{
	private CustomerManager(){} //构造函数
	private static CustomerManager instance = new CustomerManager(); //建立自类对象为实例调用
	public static CustomerManager getInstance() //获取调用实例功能
	{
		return instance; //返回自类对象
	}
	private NumberMachine CommonCustomer = new NumberMachine(); //建立取号机对象为普通客户
	private NumberMachine ExpressCustomer = new NumberMachine(); //建立取号机对象为快速客户
	private NumberMachine VIPCustomer = new NumberMachine(); //建立取号机对象为贵宾客户
	public NumberMachine getCommonCustomer() //获取普通客户功能
	{
		return CommonCustomer; //返回普通客户对象
	}
	public NumberMachine getExpressCustomer() //获取快速客户功能
	{
		return ExpressCustomer; //返回快速客户对象
	}
	public NumberMachine getVIPCustomer() //获取贵宾客户功能
	{
		return VIPCustomer; //返回贵宾客户对象
	}
}

/**
 * 定义一个方法,内部启动一个线程,根据服务窗口的类别分别循环调用三个不同的方法。
 * 定义三个方法分别对三种客户进行服务,为了观察运行效果,应详细打印出其中的细节信息。
 * 没有把VIP窗口和快速窗口做成子类,是因为实际业务中的普通窗口可以随时被设置为VIP窗口和快速窗口,
 * 当VIP窗口和快速窗口没有对应的业务时,可办理普通客户业务,一旦有对应业务,则优先办理对应业务。
 * VIP和普通客户办理时间为最大最小值范围内的随机值,快速客户办理业务的时间为最小值,最大最小值自定。
 * @author 张孝祥-黑马程序员
 * @editor 魏安-黑马程序员
 */
class ServiceWindow //服务窗口类
{
	private CustomerType type = CustomerType.COMMON; //定义枚举类变量并初始化
	private int number = 1; //定义整形数据变量为窗口数并初始化
	public CustomerType getType() //获取类型功能
	{
		return type; //返回枚举值
	}
	public void setType(CustomerType type) //设定类型功能
	{
		this.type = type; //锁定传入枚举值
	}
	public void setNumber(int number) //设定窗口数功能
	{
		this.number = number; //锁定传入窗口数值
	}
	private void commonService() //普通客户服务功能
	{
		String windowName = "第" + number + "号" + type + "窗口"; //定义字符串变量为窗口属性信息
		System.out.println(windowName + "开始获取普通任务!"); //打印信息
		Integer serviceNumber = CustomerManager.getInstance().getCommonCustomer().fetchNumber(); //定义整数型变量为服务号并得到客户经理类调用自身相应功能后执行同步取号码功能结果
		if (serviceNumber != null ) //如果服务号不为空
		{
			System.out.println(windowName + "开始为第" + serviceNumber + "号普通客户服务");	 //打印信息
			int maxRandom = Constants.MAX_SERVICE_TIME - Constants.MIN_SERVICE_TIME; //定义整形数据变量为最大随机数种子
			int serviceTime = new Random().nextInt(maxRandom) + 1 + Constants.MIN_SERVICE_TIME; //定义整形数据变量为服务时间并得到通过运算方式结果
			try //尝试执行
			{
				Thread.sleep(serviceTime); //线程休眠时间
			}
			catch (InterruptedException e) //抓捕到中断异常
			{
				e.printStackTrace(); //打印堆栈信息
			}
			System.out.println(windowName + "完成为第" + serviceNumber + "号普通客户服务,总共耗时" + serviceTime / 1000 + "秒"); //打印信息
		}
		else //否则执行
		{
			System.out.println(windowName + "没有取到普通任务,正在空闲1秒"); //打印信息
			try //尝试执行
			{
				Thread.sleep(1000); //线程休眠时间
			}
			catch (InterruptedException e) //抓捕到中断异常
			{
				e.printStackTrace(); //打印堆栈信息
			}
		}
	}
	private void expressService() //快速客户服务功能
	{
		String windowName = "第" + number + "号" + type + "窗口"; //定义字符串变量为窗口属性信息
		System.out.println(windowName + "开始获取快速任务!");	 //打印信息
		Integer serviceNumber = CustomerManager.getInstance().getExpressCustomer().fetchNumber(); //定义整数型变量为服务号并得到客户经理类调用自身相应功能后执行同步取号码功能结果
		if (serviceNumber != null) //如果服务号不为空
		{
			System.out.println(windowName + "开始为第" + serviceNumber + "号快速客户服务");	 //打印信息
			int serviceTime = Constants.MIN_SERVICE_TIME; //定义整形数据变量为服务时间并得到最小服务时间值
			try //尝试执行
			{
				Thread.sleep(serviceTime); //线程休眠时间
			}
			catch (InterruptedException e) //抓捕到中断异常
			{
				e.printStackTrace(); //打印堆栈信息
			}
			System.out.println(windowName + "完成为第" + serviceNumber + "号快速客户服务,总共耗时" + serviceTime / 1000 + "秒"); //打印信息
		}
		else //否则执行
		{
			System.out.println(windowName + "没有取到快速任务!"); //打印信息
			commonService(); //执行普通客户服务功能
		}
	}
	private void vipService() //贵宾客户服务功能
	{
		String windowName = "第" + number + "号" + type + "窗口"; //定义字符串变量为窗口属性信息
		System.out.println(windowName + "开始获取VIP任务!"); //打印信息
		Integer serviceNumber = CustomerManager.getInstance().getVIPCustomer().fetchNumber(); //定义整数型变量为服务号并得到客户经理类调用自身相应功能后执行同步取号码功能结果
		if (serviceNumber != null) //如果服务号不为空
		{
			System.out.println(windowName + "开始为第" + serviceNumber + "号VIP客户服务"); //打印信息
			int maxRandom = Constants.MAX_SERVICE_TIME - Constants.MIN_SERVICE_TIME; //定义整形数据变量为最大随机数种子
			int serviceTime = new Random().nextInt(maxRandom) + 1 + Constants.MIN_SERVICE_TIME; //定义整形数据变量为服务时间并得到通过运算方式结果
			try //尝试执行
			{
				Thread.sleep(serviceTime); //线程休眠时间
			}
			catch (InterruptedException e) //抓捕到中断异常
			{
				e.printStackTrace(); //打印堆栈信息
			}
			System.out.println(windowName + "完成为第" + serviceNumber + "号VIP客户服务,总共耗时" + serviceTime / 1000 + "秒"); //打印信息
		}
		else //否则执行
		{
			System.out.println(windowName + "没有取到VIP任务!"); //打印信息
			commonService(); //执行普通客户服务功能
		}
	}
	private Runnable ServiceType = new Runnable() //建立可运行多线程类对象为服务类型操作
	{
		@Override //系统覆写标记
		public void run() //覆写系统运行功能
		{
			while (true) //当条件为真就一直循环
			{
				switch (type) //根据传入值选择以下分支
				{
					case COMMON: //选项对应值
					commonService(); //执行普通客户服务功能
					break; //选择结束
					case EXPRESS: //选项对应值
					expressService(); //执行快速客户服务功能
					break; //选择结束
					case VIP: //选项对应值
					vipService(); //执行贵宾客户服务功能
					break; //选择结束
				}
			}
		}
	}; //匿名内部类调用方式
	public void startService() //开启服务功能
	{
		Executors.newSingleThreadExecutor().execute(ServiceType); //执行器创建单线程执行服务类型操作
	}
}

学习心得:在巨人的肩膀上,你会做得更好!

作为银行从业人员的观点,其实工作流程没有那么夸张。

主要是因为该程序要模拟客户服务的整个实际情景,所以理解起来就麻烦一点。

该程序思路还可以用于客户排队或者是某些物品的流通处理等情景,还可以进一步改进,非常不错!

说实在话,大部分行业都是务实的用人态度,IT软件编程行业就不能务实一点么?

用难题也就算了,用怪题能找什么人呢?做事还是务实一点比较好。

个人观点,牢骚满腹,呵呵!

补充一点:我既然能把所有类全部压在同一个java文件中,还懂得用public修饰符放在主函数的类那里,并不是我不懂得用开发工具,而是我明白Java的某些东西,你懂的……

原帖:http://blog.csdn.net/zhangxiaoxiang/article/details/6294132

张孝祥老师已逝,可惜!无论世人如何评价他,起码他都是个实实在在做事的人!就凭这一点,就值得世人敬佩!他真的帮助了很多人!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值