黑马程序员_7K面试题之银行业务调度系统

本文介绍了一种模拟银行业务调度系统的实现方案,包括系统逻辑、需求分析及各个类的设计细节。系统采用多线程技术模拟不同类型客户的产生和服务过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

            银行业务调度系统

一、概述

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

 

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

 

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

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

 

        VIP客户 :普通客户 :快速客户 =  1 :6 :3。

   

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

 

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

 

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

 

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


二、需求分析

由题目可以了解到不管是客户还是服务窗口,他们操作的都是同一个取票机,当客户来到银行办理业务的时候,会到取票机器那里取得一张号码,同时该号码会存储在相对应的取票器中,这时就会有对应的窗口向对应的取票器中读取存入的号码,从而有序地对用户进行操作。


   
  
 
 
由需求可以知道,我们在一台取票机中得有三个取票器,分别管理着普通客户、快速客户和VIP客户的取号,同时窗口也分为普通窗口、快速窗口和VIP窗口,规定普通窗口只能办理普通客户的手续,VIP客户可以办理VIP客户手续,如果在没有VIP客户的时候,也可以办理普通客户,快速窗口也一样,在没有快速客户的时候,也可以办理普通客户的手续,如此分析,则有取票机的结构应为这样:


一个取票机里面有三个取票器,VIP窗口和快速窗口的操作功能是一样,均为“做完自己的事,再忙其他的事”;基本流程图如下:


普通窗口和VIP、快速窗口则不一样,其基本流程图如下:


到此,几个取票器之间的基本关系就可以确立了下来了。在需求里面有提到客户服务时间与客服产生时间,这里使用线程的sleep方法来模拟为客户的服务的时间,使用jdk5的新特性来模拟客户产生的过程,在这个系统中,个人觉得的就是类与类之间的关系太过于复杂了,所以按照了个人的理解画出了类与类之间的关系图。自定义的类有:

NunberManage:产生客服和取出客服的取票器

NumberMachine:模拟了一个取票机,里面包含了三个取票器

ServiceWindow :模拟窗口去操作取票机,服务不同的客户

MainClass:初始化各种窗口,以及设计了客户已1:6:3来到银行办理业务

CustomerService:存储在各个类中要使用到的常量

WindowType:枚举类,存了三种窗口类型的对象。

很据我自己的理解得出的他们之间的关系;:


三、各个类的设计

NumberManage类的设计:

该类提供了两个方法:

getNewNumber():当有客户取服务号码的时候,产生一个号码,将此号码返回给客户,使得客服指导知己的号码,同时将这一号码存储在一个容器中,以便服务窗口能取到号码,并为相应的客户服务。

fetchNumber():为窗口调用,窗口取得集合中的号码,并为该号码对应的客户服务。

由于这里设计到了两个函数同时操作一个对象(集合),所以这里要使用同步锁,使得在某一时刻只能有一个方法区操作集合,避免了异常的产生。

该类的设计的源码为:


package cn.itcast.bank;

import java.util.ArrayList;
import java.util.List;

//这里产生为每一中类型的取票器提供两种方法,
//提供为客户取票和窗口取票两种方法

public class NumberManage {
	
	//使用一个集合,将客户产生的号码放入该集合中,方便窗口取得该号码,为客户服务
  private  List<Integer> NumberArr = new ArrayList<Integer>();
  
  //在定义个变量,用来返回客户的号码
  private int lastNumber =0;
	
	
	public synchronized Integer getNewNumber(){ //这里是两个函数同时操作同一个集合,为了避免产生异常,使用同步函数
		
		NumberArr.add(++lastNumber);   //客服取票,同时将客户所取得的号码存入集合中
		
		return lastNumber;
	
	}
	
	public synchronized Integer fetchNumber(){
		
		if(NumberArr.size() > 0){ //得闲判断是否有需要服务的客户
			
			return	NumberArr.remove(0);
			
			
		}else{
		
		
		return null;
		}
		
		
		
	}
	
	
	

}

NumberMachine类的设计:

该类模拟了一个取票机,保证该取票机只能有一个,同时也要得到该取票机中的三种取票器,

所以该类的设计就是创建NumberManage类的对象,对外提供获取该类对象的方法,同时,使用单例设计模式让本类永远都只能有一个实例对象:

该类源码为:

package cn.itcast.bank;

/*
 * 该类模拟了一个取票机,该取票机里有三个取票器,分别是普通客户取票器、VIP客户取票器和快速客户取票器
 * 
 * 三个取票器有各自的NumberManage
 * 
 * 为了产生避免产生多个相同的号码,所以这里采用了单例设计模式,也就是这里只有一个取票机
 * 
 * 
 * */


public class NumberMachine {
	
	
	//创建三个取票器
	//普通客服取票器
	private NumberManage commonCustomer = new NumberManage();
	
	//VIP客户取票器
	private NumberManage VIPCustomer = new NumberManage();
	
	
	//快速客户取票器
	private NumberManage fastCustomer = new NumberManage();
	
	
	
	
	public NumberManage getCommonCustomer() {
		return commonCustomer;
	}

	public NumberManage getVIPCustomer() {
		return VIPCustomer;
	}

	public NumberManage getFastCustomer() {
		return fastCustomer;
	}

	//控制本类永远只有一个对象,单例设计模式
	private NumberMachine(){};
	
	private static NumberMachine instance = new NumberMachine();
	
	public static NumberMachine getInstance(){
		
		return instance;
		
	}
	
	
	

}


ServiceWindow类的设计:

该类可以为各种类型的客户提供服务,也就是说这个类可以模拟不同的窗口,并为不同的客户提供服务,这里具体有什么样的窗口,还要由MainClass类中指定,这里指定了什么样的窗口应该为什么样的客户服务,使用jdk1.5的新特性,开启一个线程来执行取票任务,使用循环,不停地取票,并判断当前窗口是那种类型的窗口,使用当前窗口去执行对应的取票任务(VIP窗口在VIP取票器中取票,快速窗口在快速取票器中取票。。。。),对于VIP取票和快速取票,如果当前没有VIP客户,则VIP窗口将会为普通客户服务,快速窗口也一样,

setType:用来设置当前窗口是什么类型的,

setWinNumber:用来设置当前窗口是第几个窗口。


start();窗口开启,开始服务


CommCustomer();为普通客户提供服务,没有普通客户时,休息1s,有,为该客户服务,并在一定时间内不为其他客户服务(线程睡眠一端时间);

FastCustomer();为快速客户提供服务,有快速客户时,为快速客服提供服务,在服务期间也不为其他客户提供服务(线程睡眠一段时间),如果没有快速客户,则该快速窗口就会为普通客户提供服务,此时有普通客户,为普通客户提供服务,没有,休息1s,再继续去取快速客户,如此循环。

VipCustomer();该方法的功能和FastCustomer的功能相似;


该类的源码实现:

package cn.itcast.bank;

import java.util.Random;
import java.util.concurrent.Executors;

//模拟服务窗口


public class ServiceWindow {
	
	
	//初始化窗口
	WindowType type = WindowType.COMMON;
	
	//初始化窗口
	private int winNumber;
	
   
	//开始取票
	
	public void setType(WindowType type) {
		this.type = type;
	}

	public void setWinNumber(int winNumber) {
		this.winNumber = winNumber;
	}

	public void start(){
		//开启一个线程来执行窗口取票
		Executors.newSingleThreadExecutor().execute(new Runnable() {
			
			@Override
			public void run() {
				// TODO Auto-generated method stub
				while(true){
				switch (type) {
				case COMMON: //如果是普通窗口
					ConmmNumber();
					break;
				case FAST:
					FastNumber();
					
					break;
				case VIP:
					VipNumber();
					break;

				}
				
				}
			}
		});
		
		
	}

	protected void ConmmNumber() {
		// TODO Auto-generated method stub
		
		//获得取票机中取票器
		
		NumberManage common = NumberMachine.getInstance().getCommonCustomer();
		
		//获取该取票器中的号码
		
		Integer CustomerNumber =  common.fetchNumber();
		
		if(CustomerNumber != null){
			
			//取到号码,为该客户服务
			
			System.out.println("第"+winNumber+"号"+type+"窗口正在为"+CustomerNumber+"号普通用户服务");
			
			//服务期间,不能服务其他客户,让该线程睡眠一段时间,
			
			int Time = CustomerService.WINDOW_SERVICE_MAX_TIME-CustomerService.WINDOW_SERVICE_MIN_TIME;
			 
			int currentTime = new Random().nextInt(Time)+1 + CustomerService.WINDOW_SERVICE_MIN_TIME;
			
			
			try {
				Thread.sleep(currentTime);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			System.out.println("完成对"+CustomerNumber+"号普通客户的服务,总耗时"+currentTime/1000+"s");
			
		}else{
			
			System.out.println("第"+winNumber+"号"+type+"窗口没有取到普通客户,休息1s");
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		}
		
		
	}
	
	protected void FastNumber() {
		// TODO Auto-generated method stub
		
		//获得取票机中取票器
		
		NumberManage common = NumberMachine.getInstance().getFastCustomer();
		
		//获取该取票器中的号码
		
		Integer CustomerNumber =  common.fetchNumber();
		
		if(CustomerNumber != null){
			
			//取到号码,为该客户服务
			
			System.out.println("第"+winNumber+"号"+type+"窗口正在为"+CustomerNumber+"号快速客户服务");
			
			//服务期间,不能服务其他客户,让该线程睡眠一段时间,
			
			//int Time = CustomerService.WINDOW_SERVICE_MAX_TIME-CustomerService.WINDOW_SERVICE_MIN_TIME;
			 
	    //   int currentTime = new Random().nextInt(CustomerService.WINDOW_SERVICE_MIN_TIME)+1;
			
			
			try {
				Thread.sleep(CustomerService.WINDOW_SERVICE_MIN_TIME);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			System.out.println("完成对"+CustomerNumber+"号快速客户的服务,总耗时"+CustomerService.WINDOW_SERVICE_MIN_TIME/1000+"s");
			
		}else{
			
			System.out.println("第"+winNumber+"号"+type+"窗口没有取到"+type+"客户,可以为普通客户服务");
		     
			ConmmNumber();
		}
		
		
	}
	
	
	protected void VipNumber() {
		// TODO Auto-generated method stub
		
		//获得取票机中取票器
		
		NumberManage common = NumberMachine.getInstance().getVIPCustomer();
		
		//获取该取票器中的号码
		
		Integer CustomerNumber =  common.fetchNumber();
		
		
		if(CustomerNumber != null){
			
			//取到号码,为该客户服务
			
			System.out.println("第"+winNumber+"号"+type+"窗口正在为"+CustomerNumber+"号VIP客户服务");
			
			//服务期间,不能服务其他客户,让该线程睡眠一段时间,
			
			int Time = CustomerService.WINDOW_SERVICE_MAX_TIME-CustomerService.WINDOW_SERVICE_MIN_TIME;
			 
	        int currentTime = new Random().nextInt(Time)+1 + CustomerService.WINDOW_SERVICE_MIN_TIME;
			
			
			try {
				Thread.sleep(currentTime);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			System.out.println("完成对"+CustomerNumber+"号VIP客户的服务,总耗时"+currentTime/1000+"s");
			
		}else{
			
			System.out.println("第"+winNumber+"号"+type+"窗口没有取到"+type+"客户,可以为普通客户服务");
		     
			ConmmNumber();
		}
		
		
	}
	
	
	
	

}

MainClass类的设计:

该类就做了一些初始化啊,这里就初始化了五个普通窗口,一个快速窗口,一个VIP窗口,并产生三个新线程去模拟三种不同的客户的产生的情况,并实现

VIP客户 :普通客户 :快速客户 =  1 :6 :3。

该类源码:

package cn.itcast.bank;

import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class MainClass {
	
	
	public static void main(String[] args) {
		
		 //开启五个普通窗口,不指定则默认是普通窗口
		for(int i =1 ;i <= 5 ; i++){
			 ServiceWindow Commwindow = new ServiceWindow();
			 
			 Commwindow.setWinNumber(i);
			 
			 Commwindow.start();
			
		}
		
		
		//开启一个VIP窗口
		
		ServiceWindow Vipwindow = new ServiceWindow();
		Vipwindow.setType(WindowType.VIP);
		Vipwindow.setWinNumber(1);
		Vipwindow.start();
		
		
		//开启一个快速窗口
		ServiceWindow Fastwindow = new ServiceWindow();
		Fastwindow.setType(WindowType.FAST);
		Fastwindow.setWinNumber(1);
		Fastwindow.start();
		
		
		//开启窗口,先在就是上班时间,该有客户来办理业务了,由于三种客户之间是没有任何联系的,所以每一种客户要使用单独的线程来控制
		
		//普通客户
		Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
                new Runnable() {
					
					@Override
					public void run() {
						// TODO Auto-generated method stub
						
					Integer Customer =	NumberMachine.getInstance().getCommonCustomer().getNewNumber();
					
					System.out.println("第"+Customer+"号普通客户正在等待办理业务");
						
					}
					},
				0,
				CustomerService.HOW_TIME_ADDCUSTOMER,
				TimeUnit.SECONDS);
		//VIP客户
		Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
                  new Runnable() {
					
					@Override
					public void run() {
						// TODO Auto-generated method stub
						
					Integer Customer =	NumberMachine.getInstance().getVIPCustomer().getNewNumber();
					
					System.out.println("第"+Customer+"号VIP客户正在等待办理业务");
						
					}
					},
				0,
				CustomerService.HOW_TIME_ADDCUSTOMER * 6,
				TimeUnit.SECONDS);
		
		//快速客户
		Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
                new Runnable() {
					
					@Override
					public void run() {
						// TODO Auto-generated method stub
						
					Integer Customer =	NumberMachine.getInstance().getFastCustomer().getNewNumber();
					
					System.out.println("第"+Customer+"号快速客户正在等待办理业务");
						
					}
					},
				0,
				CustomerService.HOW_TIME_ADDCUSTOMER * 2,
				TimeUnit.SECONDS);
	
	}
 
	


}

对于CustomerService类存储的就是一些在其他类中的常量:

package cn.itcast.bank;

public class CustomerService {
	
	//一个窗口为客户服务的最大时间为
	public static final int WINDOW_SERVICE_MAX_TIME = 10000;
	
	
	//一个窗口为客户服务的最大时间为
	public static final int WINDOW_SERVICE_MIN_TIME = 1000;
	
	
	//设置多长时间增加一个客户
	public static final int HOW_TIME_ADDCUSTOMER = 1;

}

WindowType是一个枚举类,该枚举类有三个实例对象,分别是:COMMON,VIP,FAST,他们分别代表了窗口的类型为:普通类型,VIP类型和快速窗口类型,这里覆盖了他们的toString方法,

package cn.itcast.bank;

public enum WindowType {
	
	COMMON,VIP,FAST;
	
	@Override
	public String toString(){
		
		switch (this) {
		case COMMON:
		   return "普通";
			
		case VIP:
			
			return name();
		case FAST:
			
			return "快速";

		default:
			break;
		}
		
		return null;
		
	}
	
	

}












评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值