------- android培训、java培训、期待与您交流! ----------
项目需求
Ø 异步随机生成按照各个路线行驶的车辆。
例如:
由南向而来去往北向的车辆 ---- 直行车辆
由西向而来去往南向的车辆 ---- 右转车辆
由东向而来去往南向的车辆 ---- 左转车辆
...
Ø 信号灯忽略黄灯,只考虑红灯和绿灯。
Ø 应考虑左转车辆控制信号灯,右转车辆不受信号灯控制。
Ø 具体信号灯控制逻辑与现实生活中普通交通灯控制逻辑相同,不考虑特殊情况下的控制逻辑。
注:南北向车辆与东西向车辆交替放行,同方向等待车辆应先放行直行车辆而后放行左转车辆。
Ø 每辆车通过路口时间为1秒(提示:可通过线程Sleep的方式模拟)。
Ø 随机生成车辆时间间隔以及红绿灯交换时间间隔自定,可以设置。
Ø 不要求实现GUI,只考虑系统逻辑实现,可通过Log方式展现程序运行结果。
下面我将按照张孝祥老师的开发思路重新独立实现交通灯系统。
面向对象的分析与设计
项目分析的过程中,画图会有助于我们的理解。1. 在每条线路上车的数量是随机增加的,每条路线每隔一秒都会检查控制本路线的灯是否为绿,为绿时,要减少一辆车
a. 总共有12条线路,用Road类来表示线路,Road对象来表示一条线路
b. 线路上的车会随机增加,用Road对象中的一个集合来存储增加的车辆
c. 每条线路每隔一秒钟会检查该路线交通灯是否为绿,若为绿,则移除集合中的第一个元素,表示第一辆车通过了路口
2. 一个灯由绿变红时,应该将下一个方向的灯变绿。
a. 用Light类来表示交通灯,每个交通灯维护一个状态:绿或者不绿(即红),每个交通灯要有变绿和变红的方法,并且能返回自己的颜色状态。
b. 有12条路线对应12个交通灯。右拐弯的路线本来不受灯控制,为了让程序采用统一的处理方式,假设出有四个右拐弯的灯,只是这些灯为绿状态。
c. 其他8条路线的灯,它们两两成对,归为4组,所以,在编程处理时,只要从这4组中各取出一个灯,使4个灯依次变绿,与这4个灯方向相对的灯随之一同变化,因此Light类中要有一个变量来记住自己相反方向的灯,在一个Light对象的变绿和变红方法中,将对应方向的灯也变绿和变红。每个灯变红时,都伴随者下一个灯的变绿,Light类中还用一个变量来记录下一个变绿的灯。
d. 无论在程序的什么地方去获得某个方向的灯时,每次获得的都是同一个实例对象,所以Light类改用枚举来做显然具有很大的方便性,永远都只有代表12个方向的灯的实例对象。
e. 我们使用控制类LightController类,每隔10秒钟,是当前的灯有绿变红,并使下一个灯由红变绿,并设置为当前灯。
代码实现
Road类
a. Road类中的name成员变量来表示对应灯的名称,vehicles集合来存储线路中的车辆b. 在Road的构造方法中启动一个线程每隔一个随机的时间向vehicles中增加一辆车(用“路线名_id”的字符串进表示新增的车)。
c. 在Road的构造方法中启动一个定时器,每隔一秒检查该方向上的灯是否为绿,是则打印“某某车已经通过交通灯”并将第一辆车从集合中移除掉。
public class Road {
private String roadName;
private List<String> vehicles = new ArrayList<String>();
public Road(String roadName){
this.roadName = roadName;
//启动线程随机增加车辆
ExecutorService pool = Executors.newSingleThreadExecutor();
pool.execute(new Runnable(){
public void run(){
for(int i=0;;i++){
try {
Thread.sleep((new Random().nextInt(10)+1)*1000);
vehicles.add(Road.this.roadName+"_"+i);
} catch (Exception e) {
e.printStackTrace();
}
}
}
});
//每隔一秒钟检测该线路交通灯是否为绿,若然,则放行车辆
ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
service.scheduleAtFixedRate(
new Runnable(){
public void run(){
boolean isGreen = Light.valueOf(Road.this.roadName).isGreen();
if(isGreen && vehicles.size()>0){
String vehicleName = vehicles.remove(0);
System.out.println(vehicleName+"通过线路"+Road.this.roadName);
}
}
},
1,
1,
TimeUnit.SECONDS);
}
}
Light类
a. 系统中只有12条路线的灯,在程序的其他地方可以根据灯的名称就可以获得对应的灯的实例对象,所以Light类用枚举形式定义更为简单。b. 每个Light对象中的红绿状态用isGreen变量表示,选用S2N、S2W、E2W、E2N这四个方向上的Light对象依次变绿,Light对象中还要有一个opposite变量来表示它们相反方向的灯,再用一个next变量来表示此灯变红的下一个变绿的灯。这三个变量用构造方法的形式进行赋值,因为枚举元素必须在定义之后引用,所以无法再构造方法中彼此相互引用,所以,相反方向和下一个方向的灯用字符串形式表示。
c. 增加让Light变绿和变红的方法:turnGreen和turnRed,对于S2N、S2W、E2W、E2N这四个方向上的Light对象,这两个方法内部要让相反方向的灯随之变绿和变红,turnRed方法还要让下一个灯变绿。
d. 除了S2N、S2W、E2W、E2N这四个方向上的Light对象之外,其他方向上的Light对象的next和opposite属性设置为null即可,并且S2N、S2W、E2W、E2N这四个方向上的Light对象的next和opposite属性必须设置为null,以便防止turnGreen和turnRed进入死循环。
public enum Light {
//每个枚举元素各表示一个方向的控制灯
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 Light(String opposite,String next,boolean isGreen){
this.opposite = opposite;
this.next = next;
this.isGreen = isGreen;
}
private Light(){}
private boolean isGreen;
private String opposite;
private String next;
public boolean isGreen(){
return isGreen;
}
public void turnGreen(){
isGreen = true;
if(opposite != null){
Light.valueOf(opposite).turnGreen();
}
}
public Light turnRed(){
isGreen = false;
if(opposite != null){
Light.valueOf(opposite).turnRed();
}
if(next != null){
Light.valueOf(next).turnGreen();
System.out.println("线路切换");
return Light.valueOf(next);
}
return null;
}
}
LightController类
a. LightController构造方法中要设定第一个为绿的灯。b. 开启12条路线,即创建12个Road类的对象
c. LightController构造方法中启动一个定时器,每隔10秒将当前灯变红和下一个灯变绿。
public class LightControllor {
Light currentLight;
public LightControllor(){
currentLight = Light.S2N;
currentLight.turnGreen();
//开启12条路线,即创建12个Road类的对象
String[] roadNames = {"S2N","N2S","S2W","N2E","E2W","W2E","E2S","W2N","S2E","E2N","N2W","W2S"};
for(String roadName:roadNames){
new Road(roadName);
}
//每隔10秒钟进行一次红绿灯的切换
ScheduledExecutorService service = Executors.newScheduledThreadPool(1);
service.scheduleAtFixedRate(
new Runnable(){
public void run(){
currentLight = currentLight.turnRed();
}
},
10,
10,
TimeUnit.SECONDS);
}
public static void main(String[] args) {
//启动交通灯控制系统
new LightControllor();
}
}