交通燈實際上並不怎麼難,就是簡單的把這些燈分成幾組進行輪換,那些常綠的和長紅的不參加輪換。至於東南西北跟燈其實一點關係也沒有,燈是不知道東南西北的,這個管理器本身只知道下一組燈是那幾個就可以。而在實際的應用方面,常綠的燈也不見得就光是右轉,長紅的可能有很多,比如交通管理中心對道路進行調度時的調整等等。
張老師的做法並不支持丁字路口之類的特殊路口模式,所以這個管理系統的設計方面應該適合更多種類。
以下是源碼
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>