起初使用的是硬编码,跟张老师一样,不过银行的窗口可能有几十个,也可能分类的用户也不只3个,那么硬编码肯定不行,不健壮,所以还得把业务逻辑分离这样对于不同环境,只需要修改配置文件就能达成目的。
该实现支持任意多个业务窗口同时工作,支持任意多个业务类型,或者说是用户类型。同时也支持其他窗口的主要业务队列为空时进行其他业务类型处理时的优先级。
以下是源代码
import org.dom4j.DocumentException;
public class BankApp
{
public static void main(String[] args) throws DocumentException
{
ServiceManager.getInstance().readConfig("NewFile.xml");
NumberMachine.getInstance().start();
ServiceManager.getInstance().start();
}
}
import java.io.File;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Random;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
public final class ServiceManager
{
/* 保存着业务窗口的数组 */
private ServiceWindow[] windows;
/* 业务队列,根据业务类型来查找相关的队列 */
private HashMap<String, Queue<Integer>> serviceQueue;
/* 时间类型的表,用来区分不同业务的时间情况 */
private HashMap<String, String> timeType;
/* 单例模式 */
private static final ServiceManager manager = new ServiceManager();
private ServiceManager(){}
public static final ServiceManager getInstance()
{
return manager;
}
/*
* 根据设置的最大值最小值进行业务时间模拟
*
* 时间类型限定为3种,min表示最小值,max表示最大值
* normal表示随机时间,在最大最小值之间
*/
public static int min;
public static int max;
public int getTime(String type)
{
Random random = new Random();
String time = timeType.get(type);
if(time.equals("normal"))
{
return Math.abs(random.nextInt() % (max - min)) + min;
}
else if(time.equals("min"))
{
return min;
}
else if(time.equals("max"))
{
return max;
}
return -1;
}
/**
* 根据配置文件进行初始化程序
*/
public void readConfig(String fileName) throws DocumentException
{
SAXReader reader = new SAXReader();
Document document = reader.read(new File(fileName));
Element root = document.getRootElement();
//业务声明部分
Element service_type = root.element("ServiceType");
int service_length = Integer.parseInt(service_type.attribute("length").getText());
serviceQueue = new HashMap<String, Queue<Integer>>(3);
timeType = new HashMap<String, String>(3);
min = Integer.parseInt(service_type.attribute("min").getText());
max = Integer.parseInt(service_type.attribute("max").getText());
int i = 0;
Iterator<Element> iterator = service_type.elementIterator("Service");
for (; i < service_length && iterator.hasNext(); i++)
{
Element servicElement = iterator.next();
timeType.put(servicElement.attribute("name").getText(), servicElement.attribute("time").getText());
Queue<Integer> service_queue = new LinkedList<Integer>();
serviceQueue.put(servicElement.attribute("name").getText(), service_queue);
System.out.println("Service{name="+servicElement.attribute("name").getText()+" time="+servicElement.attribute("time").getText()+"}");
}
System.out.println("======================================================>");
//业务窗口部分
Element service_windows = root.element("ServiceWindow");
windows = new ServiceWindow[Integer.parseInt(service_windows.attribute("length").getText())];
i = 0;
for (iterator = service_windows.elementIterator("Window"); i < windows.length && iterator.hasNext(); i++)
{
Element window = iterator.next();
windows[i] = new ServiceWindow();
windows[i].setName(window.attribute("name").getText());
windows[i].setId(window.attribute("id").getText());
windows[i].setNormal(window.attribute("normal").getText());
windows[i].setIdle(window.attribute("idle").getText());
System.out.println(windows[i].toString());
}
System.out.println("======================================================>");
}
/*
* 获取下一个业务,返回的是该客户的队列编号
*/
public Integer getNextService(String type)
{
synchronized (serviceQueue)
{
return serviceQueue.get(type).poll();
}
}
/*
* 从号码机发来的用户进入队列请求
*/
public void putService(String type, Integer number)
{
serviceQueue.get(type).add(number);
System.out.println(""+number+"号"+type+"用户进入队列");
}
/*
* 所有业务窗口开始工作
*/
public void start()
{
ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(windows.length);
for (ServiceWindow window : windows)
{
threadPool.execute(window);
}
}
}
import java.util.Random;
import java.util.concurrent.Executors;
public class NumberMachine
{
/* 单例模式 */
private NumberMachine(){}
private static NumberMachine machine = new NumberMachine();
public static NumberMachine getInstance()
{
return machine;
}
/* 用来计算当前队列编号,该方法会将编号提交给业务管理器
* 然后进入队列进行等待,直到有业务窗口拿到这个编号
*/
int curr_num = 1;
public void NextNumber(String type)
{
ServiceManager.getInstance().putService(type, curr_num++);
}
/* 模拟1:6:3的客户业务比例,尽可能的随机模拟
* 每10个客户一轮
*/
String[] customers = {"common","common","common","common","common","common",
"express","express","express","vip"};
public String poll(int index)
{
String[] tmp = new String[customers.length - 1];
System.arraycopy(customers, 0, tmp, 0, index);
System.arraycopy(customers, index+1, tmp, index, customers.length-index-1);
String customer = customers[index];
customers = tmp;
return customer;
}
/* 启动号码机 */
public void start()
{
Executors.newSingleThreadExecutor().execute(new Runnable()
{
@Override
public void run()
{
while(true)
{
Random random = new Random();
String customer = null;
if(customers.length == 0)
{
customers = new String[]{"common","common","common","common","common","common",
"express","express","express","vip"};
}
customer = poll(Math.abs(random.nextInt() % customers.length));
NextNumber(customer);
try
{
Thread.sleep(200);
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
});
}
}
public class ServiceWindow implements Runnable
{
private String name = null;
private String id = null;
private String normal = null;
private String idle = null;
public void setName(String name)
{
this.name = name;
}
public void setId(String id)
{
this.id = id;
}
public void setNormal(String normal)
{
this.normal = normal;
}
public void setIdle(String idle)
{
this.idle = idle;
}
@Override
public String toString()
{
return new StringBuffer().append("ServiceWindow{").append("name=").append(name).append(" id=").append(id)
.append(" normal=").append(normal).append(" idle=").append(idle).append("}").toString();
}
@Override
public void run()
{
Integer num;
int time = 1000;
while(true)
{
//如果队列里没有当前窗口类型的客户,则选择空闲时业务处理
A:if((num = ServiceManager.getInstance().getNextService(normal)) != null)
{
time = ServiceManager.getInstance().getTime(normal);
System.out.println(""+id+"号"+name+"正在处理"+ num+"号"+normal+"用户的业务,需要"+time+"ms");
}
//遍历所有的空闲业务类型,如果都没有客户等待,则进入等待
else
{
String[] idles = idle.split(",");
for (String string : idles)
{
if((num = ServiceManager.getInstance().getNextService(string)) != null)
{
time = ServiceManager.getInstance().getTime(string);
System.out.println(""+id+"号"+name+"正在处理"+ num+"号"+string+"用户的业务,需要"+time+"ms");
break A;
}
}
time = 1000;
System.out.println(""+id+"号"+name+"正在等待"+time+"ms");
}
//根据相关的业务处理来进行适当的休眠
//模拟实际的业务处理时间
try
{
Thread.sleep(time);
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
配置文件NewFile.xml
<?xml version="1.0" encoding="UTF-8"?>
<Bank>
<ServiceType length="3" min="500" max="2000">
<Service name="common" time="normal"/>
<Service name="express" time="min"/>
<Service name="vip" time="normal"/>
</ServiceType>
<ServiceWindow length="6">
<Window name="普通窗口" id="1" normal="common" idle="common" />
<Window name="普通窗口" id="2" normal="common" idle="common"/>
<Window name="普通窗口" id="3" normal="common" idle="common"/>
<Window name="普通窗口" id="4" normal="common" idle="common"/>
<Window name="快速窗口" id="5" normal="express" idle="common"/>
<Window name="VIP窗口" id="6" normal="vip" idle="express,common"/>
</ServiceWindow>
</Bank>