交通燈管理系統
1.模擬實現十字路口的交通燈管理系統邏輯,具體需求如下:
1.1異步隨機生成按照各個路線行駛的車輛:
例如:1.1.1.由南向而來去往北向的車輛---- 直行車輛。
1.1.2.由西向而來去往南向的車輛---- 右轉車輛。
1.1.3.由東向而來去往南向的車輛---- 左轉車輛。
1.1.4.信號燈忽略黃燈,只考慮紅燈和綠燈。
1.1.5.應考慮左轉車輛控制信號燈,右轉車輛不受信號燈控制。
1.1.6.具體信號燈控制邏輯與現實生活中普通交通燈控制邏輯相同,不考慮特殊情況下的控制邏輯。
2.思考:車子由什麼產生?產生的車子存儲在什麼裏面?怎麼產生車?
2.1.信號燈忽略黃燈,只考慮紅燈和綠燈。
2.2.應考慮左轉車輛控制信號燈,右轉車輛不受信號燈控制。
3.思路:考慮右轉的燈都爲長綠燈,表示車隨時可以右轉
3.1.具體信號燈控制邏輯與現實生活中普通交通燈控制邏輯相同,不考慮特殊情況下的控制邏輯。
3.2.注:南北向車輛與東西向車輛交替放行,同方向等待車輛應先放行直行車輛而後放行左轉車輛。
3.3. 每輛車通過路口時間爲1秒(提示:可通過線程Sleep的方式模擬)。
4.思考:車開過路口這個操作怎麼實現?在哪裏實現?
4.1. 隨機生成車輛時間間隔以及紅綠燈交換時間間隔自定,可以設置。
4.2.不要求實現GUI,只考慮系統邏輯實現,可通過Log方式展現程序運行結果。
5. 邏輯中的12個方向的燈:
5.1.S2N(南到北),S2W(南到西),E2W(東到西),E2S(東到南)//主要的需要操作的四個燈,它控制通往四個方向的車。
5.2.N2S(北到南),N2E(北到東),W2E(西到東),W2N(西到北)//前面四個燈對應的反向燈,讓它們依託於前面四個燈來運作。
5.3.S2E(南到東),N2W(北到西),E2N(東到北),W2S(西到南)//四個右轉燈,它們長亮。
6. 排除4個長亮燈,我們需要處理的燈有8個燈,不過,每一個燈都有反向的燈。比如S2N(南到北)和N2S(北到南)。這樣的 話,就表示,S2N綠燈的話,那麼N2S也是綠燈。這樣的話,也就是說,剩下的8個燈中,有四個燈可以依託於它的反向 燈的運作來進行相同的運作,即它的反向燈綠,那麼它綠,它的反向燈紅,那麼它紅。
7. 在這裏車子可以用一個String來表示,根據不同的燈對應的路線,產生這條路線上的車。可以考慮用12個線程來產生相 對應的車。創建一個Road類,該類在構造函數中接受一個表示路線的StringroadName,
比如:
this.roadName=roadName; 然後根據傳入的路線,來創建這條路線上的車,並把String表示的車存入這條路線上的 ArrayList中。通過它的remove方法來移除這條路線上的車子。不過再移除的時候,需要先判斷當前路線上的燈是否 爲綠燈,綠燈才能移。車子移除出去,就表示車子開過路口了。這個操作可以通過定時器完成。
8. 燈控制器用於操作燈變化的時間,多長時間換下一個燈綠等等。
9. 一共需要創建三個類:燈(用枚舉),路,燈控制器。
類的編碼實現:
9.1.Road類
9.1.1.每個Road對象都有一個name成員變量來代表方向,有一個vehicles成員變量來代表方向上的車輛集合。
9.1.2.在Road對象的構造方法中啓動一個線程每隔一個隨機的時間向vehicles集合中增加一輛車(用一個“路線名 _id”形式的字符串進行表示)。
9.1.3.在Road對象的構造方法中啓動一個定時器,每隔一秒檢查該方向上的燈是否爲綠,是則打印車輛集合和將集 閤中的第一輛車移除掉。
package com.manage.system.taffic;
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;
/**
* 每個Road對象代表一條路,一共有12個路的Road實例對象
* 每條路線上隨機增加新的車輛,增加到一個集合中
* 每條路每隔一秒就會檢測這條路上的燈是否爲綠色,是則將本路線中的集合中的車移除一輛
*/
//路的對象,控制路上的車在規定時間間隔內讓車隨機通過
public class Road {
private List<String> vechicles = new ArrayList<String>();//將路上的車放入鏈表中
private String name;//路的名字,路名與燈名應該相同
//在構造函數中創建線程
public Road(String name){
this.name = name;
ExecutorService pool = Executors.newSingleThreadExecutor();//產生一個線程池對象實例
//在類部內中使用線程池隨機創建路上的車輛
pool.execute(new Runnable() {//在線程池中調用線程實例來產生路上的車
@Override
public void run() {//重寫Run方法
for(int i=1;i<1000;i++){//產生999輛車
try {
Thread.sleep((new Random().nextInt(10)+1) * 1000);//線程每隔1到10秒 之內產生一輛車
} catch (InterruptedException e) {
e.printStackTrace();
}
vechicles.add(Road.this.name+"_"+i);//將產生的車放入鏈表中
}
}
});
//創建定時器,每隔1秒中該路若爲綠燈則通過一輛車
ScheduledExecutorService timer = Executors.newScheduledThreadPool(1);//創建一個定時器
timer.scheduleAtFixedRate(new Runnable() {//創建並執行一個在給定初始延遲後首次啓用的定期操作
@Override
public void run() {//操作命令
if(vechicles.size()>0){
boolean lighted = Lamp.valueOf(Road.this.name).isLighted();//通過路的名字與燈的名字獲取該條路上的燈的狀態
if(lighted){//若這條路的燈是綠色則該路上的車每隔1秒通過
System.out.println(vechicles.remove(0)+" is"+" traversing!");
}
}
}
},
1,
1,
TimeUnit.SECONDS);//設置燈改變的時間間隔爲1秒
}
}
9.2.Lamp類
9.2.1.系統中有12個方向上的燈,在程序的其他地方要根據燈的名稱就可以獲得對應的燈的實例對象,綜合這些因 素,將Lamp類用java5中的枚舉形式定義更爲簡單。
9.2.2.每個Lamp對象中的亮黑狀態用lighted變量表示,選用S2N、S2W、E2W、E2N這四個方向上的Lamp對象依 次輪詢變亮,Lamp對象中還要有一個oppositeLampName變量來表示它們相反方向的燈,再用一個 nextLampName變量來表示此燈變亮後的下一個變亮的燈。這三個變量用構造方法的形式進行賦值,因爲枚舉 元素必須在定義之後引用,所以無法再構造方法中彼此相互引用,所以,相反方向和下一個方向的燈用字符串 形式表示。
9.2.3.增加讓Lamp變亮和變黑的方法:light和blackOut,對於S2N、S2W、E2W、E2N這四個方向上的Lamp對象, 這兩 個方法內部要讓相反方向的燈隨之變亮和變黑,blackOut方法還要讓下一個燈變亮。
9.2.4.除了S2N、S2W、E2W、E2N這四個方向上的Lamp對象之外,其他方向上的Lamp對象的nextLampName和 oppositeLampName屬性設置爲null即可,並且S2N、S2W、E2W、E2N這四個方向上的Lamp對象的 nextLampName和oppositeLampName屬性必須設置爲null,以便防止light和blackOut進入死循環。代碼如下:
package com.manage.system.taffic;
//用枚舉來創建燈對象,一共有12盞燈
public enum Lamp {
S2N("N2S","S2W",false),S2W("N2E","E2W",false),E2W("W2E","E2S",false),E2S("W2N","S2N",false),//以這四盞燈爲基礎
N2S(null,null,false),N2E(null,null,false),W2E(null,null,false),W2N(null,null,false),
S2E(null,null,true),E2N(null,null,true),N2W(null,null,true),W2S(null,null,true);
private boolean lighted;//表示燈的狀態,false爲紅燈,true爲綠燈
private String opposite;//表示對面方向的燈
private String next;//表示下一個方向的燈
private Lamp(){
}
private Lamp(String opposite , String next,boolean lighted){
this.lighted = lighted;
this.next = next;
this.opposite = opposite;
}
public boolean isLighted(){//檢測該燈的狀態
return lighted;
}
public void light(){//將該燈變爲綠色
this.lighted = true;
if(opposite!=null){
Lamp.valueOf(opposite).light();
}
System.out.println(name()+" lamp is green:此時應該有六個方向的路有車通過。");
}
public Lamp blackOut(){//將該燈變紅色,將下一個方向的燈變綠
this.lighted = false;
if(opposite!=null){
Lamp.valueOf(opposite).blackOut();
}
Lamp nextLamp = null;
if(next!=null){
nextLamp = Lamp.valueOf(next);
nextLamp.light();
System.out.println("綠燈從"+name()+"-------------->切換爲"+next);
}
return nextLamp;
}
}
9.3.LampController類
9.3.1.整個系統中只能有一套交通燈控制系統,所以,LampController類最好是設計成單例。
9.3.2.LampController構造方法中要設定第一個爲綠的燈。
9.3.3.LampController對象的start方法中將當前燈變綠,然後啓動一個定時器,每隔10秒將當前燈變紅和將下一個 燈變綠。
代碼如下:
package com.manage.system.taffic;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
//控制燈的類
public class LampController {
private Lamp currentLamp;//表示當前正在控制的燈
public LampController(){
currentLamp = Lamp.S2N;//初始化第一個燈爲S2N
currentLamp.light();//將該燈變綠
//創建一個定時器,定時器中只有一個線程,每隔10秒改變當前燈與下一個燈的狀態,
ScheduledExecutorService timer = Executors.newScheduledThreadPool(1);
timer.scheduleAtFixedRate(
new Runnable() {
@Override
public void run() {
currentLamp = currentLamp.blackOut();//將該燈變紅並且得到下一個燈
}
},
10,
10,
TimeUnit.SECONDS);
}
}
9.4.MainClass類
9.4.1.用for循環創建出代表12條路線的對象。
9.4.2.接着創建出LampController對象。
package com.manage.system.taffic;
public class MainClass {
public static void main(String[] args) {
String[] directions = {"S2N","S2W","E2W","E2S","N2S","N2E","W2E","W2N","S2E","E2N","N2W","W2S"};
for(int i=0;i<directions.length;i++){
new Road(directions[i]);
}
new LampController();
}
}