交通灯管理系统
需求说明:
模拟实现十字路口的交通灯管理系统逻辑,具体需求如下:
Ø 异步随机生成按照各个路线行驶的车辆。
例如:
由南向而来去往北向的车辆 ---- 直行车辆
由西向而来去往南向的车辆 ---- 右转车辆
由东向而来去往南向的车辆 ---- 左转车辆
。。。
Ø 信号灯忽略黄灯,只考虑红灯和绿灯。
Ø 应考虑左转车辆控制信号灯,右转车辆不受信号灯控制。
Ø 具体信号灯控制逻辑与现实生活中普通交通灯控制逻辑相同,不考虑特殊情况下的控制逻辑。
注:南北向车辆与东西向车辆交替放行,同方向等待车辆应先放行直行车辆而后放行左转车辆。
Ø 每辆车通过路口时间为1秒(提示:可通过线程Sleep的方式模拟)。
Ø 随机生成车辆时间间隔以及红绿灯交换时间间隔自定,可以设置。
Ø 不要求实现GUI,只考虑系统逻辑实现,可通过Log方式展现程序运行结果。
对需求说明进行面向对象的分析
1.通读说明后,发现系统中所涉及到的元素有 交通灯 , 路 , 和车,车载路面上走,相当于车是路中的元素,在需求说明的例子中可以看出,路是分不同方向的从实际情况出发,一个十字路口有12个方向的,其中有四个右转方向不受红绿灯的控制可直接同行,为了程序的完整性,我们分别为这12个方向设置一个交通灯来控制着12个方向的车流,上面说到路由方向,而路的车辆又是由等来控制,那就把灯分为不同的方法来操作不同名称(以方向命名的路)的路。
总结前面的思路就是:不同方向的灯来控制对应名称的路上的车的同行。
2.类的抽取
首先是可以确定的"路"和"灯"这两个类,其次还需要一个控制单元来控制着两中事物的行为,即"控制器",另外还需要一个"启动单元"来启动控制单元,使程序开始运行
3.类的具体设计
"灯"类(Lamp):
首先,由于灯被分为12个方向,即有12个不同的灯,我们想到用枚举类来表示灯(Lamp)这个类,因为枚举类中的每一个元素都是一个对象。
其次,由实际情况可知,12个方向去除4个右转方向还有8个方向,而这8个方向又是两两对应的,即
南-->北 对应 北-->南
东-->西 对应 西-->东
西-->北 对应 东-->南
北-->东 对应 南-->西
每两个对应的方向的信号灯总是相同的,即同绿 或 同红,
*去除四个右拐方向,从这8个方向选出四个方向作为造作对象另外四个方向以这四个对象为参照来进行控制。
*********************************************************
那么每一个灯(Lamp)应该具有的属性有:
对应的灯(opposite):即与当前方向的灯相对应的灯(其中一个方向的灯有对应的灯,那么该方向对应方向的灯就不能有对应的灯,因为我们是选择当前方向灯作为基准,如果它对应的灯也存在对应的灯,那么在操作的时候就会陷入死循环)
下一个灯(next):当信号灯发生变化时,当前的灯要知道他的下一个灯是哪个方向的以便进行操作。
当前灯的状态(lighted):标记当前的灯是为红灯还是为绿灯(绿灯为true,红灯为false)
具体业务流程:
当前的灯要从绿灯变为红灯(green-->red):如果当前的灯有对应的灯,则把对应的灯也变成红灯。如果当前的灯有下一个灯则把下一个灯变成绿灯。
当前的灯要从红灯变为绿灯(red-->green):如果当前的灯有对应的灯,则把对应的等也变成绿灯。
*********************************************************
路(Road):
路有一个名字属性,按照方向进行划分。
还有一个车的集合属性,用来表示当前路上的车
每一个对应的路对象都要对自己进行维护,即按照一定的时间间隔向陆中添加车辆,同时,当这条路上的灯变为绿灯时要按每秒钟一辆车的速度进行同行
*********************************************************
控制器(Controllor)
控制器有一个指定当前灯的对象的引用,用来记录绿色的灯,每一次灯在变红时都返回下一个变绿的灯的对象。
然后控制器按一定的时间间隔对当前的绿灯进行变红操作
*********************************************************
程序源码如下所示:
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);
//定义Lamp的成员变量
private String oppsite; //对应的灯
private String next; //下一个灯
private boolean lighted; //当前等的状态
//枚举类的构造方法一定要设为私有类型
private Lamp(String opposite, String next, boolean lighted){
this.oppsite = opposite;
this.next = next;
this.lighted = lighted;
}
//提供获取灯的状态的方法
public boolean isLighted(){
return lighted;
}
//将等设置为红灯的方法
public Lamp black(){
//将当前灯设置为红灯
this.lighted = false;
//判断是否有对应的灯,如果有则把对应的等也设置成红灯
if(this.oppsite != null){
Lamp.valueOf(oppsite).black();
}
Lamp nextL = null;
//判断是否有下一个灯,如果有则把下一个灯变成绿灯
if(this.next != null){
nextL = Lamp.valueOf(next);
nextL.lighted();
System.out.println("绿灯从" + name() + "切换为 " + next);
}
return nextL;
}
//设置把灯变为绿灯的方法
public void lighted(){
this.lighted = true;
//判断是否有对对应的灯,如果有则把对应的灯变成绿灯
if(this.oppsite != null){
Lamp.valueOf(oppsite).lighted();
System.out.println(name() + "亮了, 下面可以看到有六个方向的汽车可以穿过");
}
}
}
import java.util.*;
import java.util.concurrent.*;
public class Road {
//定义一个可以存储路上车辆的集合,车辆用一个String代替,命名规则为 方向_编号
private List<String> vechiles = new ArrayList<String>();
//定义自己的名称
private String roadName = null;
//在构造函数中对路名进行初始化
public Road(String roadName){
this.roadName = roadName;
//定义一个线程,用于向路上添加车辆,频率为1 ~ 5秒钟添加一辆车
ExecutorService es = Executors.newSingleThreadExecutor();
//定义线程的执行代码
es.execute(new Runnable(){
public void run(){
for(int i = 1;i < 5000;i ++){
try {
Thread.sleep((new Random().nextInt(5)+1) * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
vechiles.add(Road.this.roadName + "_" + i);
}
}
});
//定义一个用于控制在绿灯情况下车以固定频率进行通过
ScheduledExecutorService ses = Executors.newScheduledThreadPool(1);
//定义线程的执行代码
ses.scheduleAtFixedRate(new Runnable(){
public void run(){
//先判断当前方向的路上是否有车
if(vechiles.size() > 0){
boolean currentLamp = Lamp.valueOf(Road.this.roadName).isLighted();
if(currentLamp){
System.out.println(vechiles.remove(0) + " is passing..");
}
}
}
}, 1, 1, TimeUnit.SECONDS);
}
}
import java.util.concurrent.*;
public class Controllor {
private Lamp currentLamp = null;
public Controllor(){
//对一个方向的灯进行点亮操作
currentLamp = Lamp.S2N;
currentLamp.lighted();
System.out.println("Controlar is started..");
//定义一个定时器对灯的转换情况进行控制
ScheduledExecutorService ses = Executors.newScheduledThreadPool(1);
ses.scheduleAtFixedRate(new Runnable(){
public void run(){
System.out.println("lamp turned");
currentLamp = currentLamp.black();
}
}, 5, 5, TimeUnit.SECONDS);
}
}
public class StartClass {
public static void main(String[] args) {
String[] roadName = {"S2N","S2W","E2W","E2S","N2S","N2E",
"W2E","W2N","S2E","E2N","N2W","W2S"};
for(int i = 0;i < roadName.length;i ++){
new Road(roadName[i]);
}
new Controllor();
}