交通灯实际上并不怎么难,就是简单的把这些灯分成几组进行轮换,那些常绿的和长红的不参加轮换。至于东南西北跟灯其实一点关系也没有,灯是不知道东南西北的,这个管理器本身只知道下一组灯是那几个就可以。而在实际的应用方面,常绿的灯也不见得就光是右转,长红的可能有很多,比如交通管理中心对道路进行调度时的调整等等。
张老师的做法并不支持丁字路口之类的特殊路口模式,所以这个管理系统的设计方面应该适合更多种类。
以下是源码
package org.sky.traffic;
import org.dom4j.DocumentException;
public class TrafficApp
{
public static void main(String[] args) throws DocumentException
{
LampManager.getInstance().readConfig("NewFile.xml");
LampManager.getInstance().start();
/*产生12个方向的路线*/
String [] directions = new String[]{
"s2n","s2w","e2w","e2s","n2s","n2e","w2e","w2n","s2e","e2n","n2w","w2s"
};
for(int i=0;i<directions.length;i++){
new Road(directions[i]);
}
}
}
package org.sky.traffic;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
public class LampManager
{
//单例模式的交通灯管理器
private static LampManager manager = new LampManager();
private LampManager(){}
public static final LampManager getInstance()
{
return manager;
}
/* 根据配置文件中的交通灯组进行轮换,最后一组时
* 回到第一组,实际上还是循环链表好一些
*/
private int groupIndex = 0;
public void nextGroup()
{
String[] curr = lampGroup.get(groupIndex).split(",");
groupIndex = ++groupIndex == lampGroup.size() ? 0 : groupIndex;
String[] next = lampGroup.get(groupIndex).split(",");
System.out.println("==============================================>");
for (String string : curr)
{
lamps.get(string).nextLampLight();
System.out.print(string + " ");
}
System.out.println("blackout");
for (String string : next)
{
lamps.get(string).nextLampLight();
System.out.print(string + " ");
}
System.out.println("lighted");
}
/* 检查灯是否绿灯 */
public boolean isLighted(String key)
{
return lamps.get(key).isLighted();
}
/* 启动交通灯管理器 */
public void start()
{
ScheduledExecutorService timer = Executors.newScheduledThreadPool(1);
timer.scheduleAtFixedRate(new Runnable()
{
public void run()
{
nextGroup();
}
},10,10,TimeUnit.SECONDS);
System.out.println("==============================================>");
System.out.println("e2s w2n lighted");
}
/* 一个灯的集合用来查询灯的情况 */
private HashMap<String, Lamp> lamps = new HashMap<String, Lamp>(12);
/* 屏蔽列表其实没有真正实现,其实应该在常绿和长红的灯不参见轮换
* 现在这种做法只是通过不写进配置文件来达到的
*/
private ArrayList<String> alwaysGreen = new ArrayList<String>();
private ArrayList<String> alwaysRed = new ArrayList<String>();
private ArrayList<String> lampGroup = new ArrayList<String>();
/**
* 读取交通灯配置文件
* 该方法依赖于Dom4j框架
*/
public void readConfig(String fileName) throws DocumentException
{
SAXReader reader = new SAXReader();
Document document = reader.read(new File(fileName));
Element root = document.getRootElement();
Element lampList = root.element("LampList");
for (Iterator<Element> iterator = lampList.elementIterator(); iterator.hasNext();)
{
Element lamp = iterator.next();
String name = lamp.attribute("name").getValue();
boolean lighted = Boolean.parseBoolean(lamp.attribute("lighted").getValue());
lamps.put(name, new Lamp(lighted));
}
/*
* 初始化始终为绿灯的列表
*/
Element alwaysGreen = root.element("AlwaysGreen");
String[] greens = alwaysGreen.getText().split(",");
for (String string : greens)
{
this.alwaysGreen.add(string);
}
/*
* 初始化始终为红灯的列表
*/
Element alwaysRed = root.element("AlwaysRed");
String[] reds = alwaysRed.getText().split(",");
for (String string : reds)
{
if(!"".equals(string))
{
this.alwaysRed.add(string);
}
}
//初始化交通组轮换组
Element lampGroup = root.element("LampGroup");
for (Iterator<Element> iterator = lampGroup.elementIterator(); iterator.hasNext();)
{
String group = iterator.next().getText();
this.lampGroup.add(group);
}
}
}
package org.sky.traffic;
public class Lamp
{
private boolean lighted;
public Lamp(boolean lighted)
{
this.lighted = lighted;
}
public boolean isLighted()
{
return lighted;
}
public void nextLampLight()
{
lighted = !lighted;
}
}
package org.sky.traffic;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class Road
{
private List<String> vechicles = new ArrayList<String>();
private String name = null;
public Road(String name)
{
this.name = name;
// 模拟车辆不断随机上路的过程
ExecutorService pool = Executors.newSingleThreadExecutor();
pool.execute(new Runnable()
{
public void run()
{
for (int i = 1; i < 1000; i++)
{
try
{
Thread.sleep((new Random().nextInt(10) + 1) * 1000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
vechicles.add(Road.this.name + "_" + i);
}
}
});
// 每隔一秒检查对应的灯是否为绿,是则放行一辆车
ScheduledExecutorService timer = Executors.newScheduledThreadPool(1);
timer.scheduleAtFixedRate(new Runnable()
{
public void run()
{
if (vechicles.size() > 0)
{
boolean lighted = LampManager.getInstance().isLighted(vechicles.get(0).substring(0,3));
if (lighted)
{
System.out.println(vechicles.remove(0) + " is traversing !");
}
}
}
}, 1, 1, TimeUnit.SECONDS);
}
}
配置文件NewFile.xml
<?xml version="1.0" encoding="UTF-8"?>
<TrafficLamp>
<LampList>
<Lamp name="e2n" lighted="true"/>
<Lamp name="n2w" lighted="true"/>
<Lamp name="w2s" lighted="true"/>
<Lamp name="s2e" lighted="true"/>
<Lamp name="e2s" lighted="true"/>
<Lamp name="w2n" lighted="true"/>
<Lamp name="s2w" lighted="false"/>
<Lamp name="n2e" lighted="false"/>
<Lamp name="e2w" lighted="false"/>
<Lamp name="w2e" lighted="false"/>
<Lamp name="s2n" lighted="false"/>
<Lamp name="n2s" lighted="false"/>
</LampList>
<AlwaysGreen>e2n,n2w,w2s,s2e</AlwaysGreen>
<AlwaysRed></AlwaysRed>
<LampGroup>
<Group>e2s,w2n</Group>
<Group>s2w,n2e</Group>
<Group>e2w,w2e</Group>
<Group>s2n,n2s</Group>
</LampGroup>
</TrafficLamp>