交通灯管理系统
项目需求
模拟实现十字路口的交通灯管理系统逻辑,具体需求如下:
1, 异步随机生成按照各个路线行驶的车辆
例如:
由南向而来去往北边的车辆……直行车辆
由西向而来去往南向的车辆……右转车辆
……
2, 信号灯忽略黄灯,只考虑红灯和绿灯。
3, 应考虑左转车辆控制信号灯,右转车辆不受信号灯控制。
4, 具体信号灯控制逻辑与现实生活中普通交通灯控制逻辑相同,不考虑特殊情况下的控制逻辑(两相对方向交替放行,同方向直行后再放行左转的车辆)。
5, 每辆车通过路口时间为1秒(提示:可通过线程sleep的方式模拟)。
6, 随即生成车辆时间间隔以及红绿灯交换时间间隔自定,可以设置。
不要求实现GUI,只考虑系统逻辑实现,可通过Log方式展现程序运行结果。
通过对以上对需求的分析以及与实际情况的结合,可将此路况简化为如下的模型:
结合实际的经验我们知道南北、东西方向可以简化的,当由南向北直行时,由北向南亦能直行,而由南向西转弯时由北向东亦能转弯,对于东西走向也是如此,所以我们在考虑时可以将上面的路线进行简化,只考虑由南直行和左拐两条以及由东直行和左拐两条共四条路线的切换,也即图上标记了①②③④的四条路线。
面向对象的分析与设计
对象:红绿灯、灯控制系统、汽车、道路。
过程分析:灯变绿后,车可以通行,但是还应看前面是否有车,而这又应该调用路的方法,因为路上存储着车,而车在这里只是体现出穿过路口的过程,并不需要进行单独设计一个对象,所以对红绿灯、灯控制系统、道路三个对象进行设计就可以了。
在面向对象的设计中,我们如何把握一个动作(方法)到底是谁提供的呢?这里就有一个思想:谁拥有数据,谁就对外提供这些数据的方法。如以下几个经典的案例:
1, 人在黑板上画圆
这里花园的方法到底是谁提供的呢?分析后我们可以知道画圆要使用圆心坐标和半径两个数据,而这两个数据是圆的数据(基本属性),所以,画圆这个方法是圆提供的,人只是调用了它。
2, 司机刹车
刹车这一动作是谁为我们提供的呢?当然是车了,这里的司机只是调用的车的刹车这一方法。
3, 售货员打印小票统计顾客消费金额
这里的统计顾客消费金额的这一方法是小票提供的,而售货员只是调用了票据对象的计算总额的方法计算出总额。
每个对象的设计
灯:
设计一个Lamp来表示一个交通灯,每个交通灯都维护一个状态,有12条路线,就应该有12个灯,考虑用枚举,基于在需求部分的简化图我们知道,考虑四个灯就可以了。细节是:
当本方向(南北向)的灯边亮的时候,跟我对应方向上的灯也应该变亮,同样当我变红的时候对应的方向上也应该变红,而此时就应该将下一个方向(东西向)上的灯变绿。所以灯里至少应该有两个方法,两个变量。一个是自己对面方向的灯,一个是自己下一个方向上的灯。另外加上一个自己灯的状态,总共就有三个变量。
用枚举来表示各个方向上的控制灯:三个参数分别表示(相反方向灯,下一个灯,灯是否为绿灯)
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);
public void light()//当某个灯变绿时,它对应方向的灯也要变绿
{
//方法主体
}
public Lamp blackOut()//某个灯变红时,对应方向的灯也要变红,并且下一个方向的灯要变绿
{
//return下一个要变绿的灯
}
控制系统:
在控制系统中肯定要有一个变量记住当前变绿的灯是哪一个,同样会有一个监视器,待当前的灯时间到就将其置为红灯,于此同时应该将下一个灯置为绿灯,并用监视器记住这个绿灯,然后就循环的往复。
public LampController(){
//刚开始让由南向北的灯变绿;
currentLamp = Lamp.S2N;
currentLamp.light();
/*每隔10秒将当前绿灯变为红灯,并让下一个方向的灯变绿*/
ScheduledExecutorService timer = Executors.newScheduledThreadPool(1);//线程池
timer.scheduleAtFixedRate(new Runnable()
{
publicvoid run(){
System.out.println("来啊");
currentLamp= currentLamp.blackOut();
}
},
10,
10,
TimeUnit.SECONDS);
}
路:
设计一个Road类来表示路线,每个Road对象代表一条路线,总共有12条路线,即系统中总共要产生12个Road实例对象。每条路线上随机增加新的车辆,增加到一个集合中保存。每条路线每隔一秒都会检查控制本路线的灯是否为绿,是则将本路线保存车的集合中的第一辆车移除,即表示车穿过了路口。
/*模拟车辆不断随机上路的过程 */
ExecutorService pool =Executors.newSingleThreadExecutor();//
pool.execute(new Runnable(){
public voidrun(){
for(inti=1;i<1000;i++){
try{
Thread.sleep((newRandom().nextInt(10) + 1) * 1000)//小细节
}
catch (InterruptedExceptione) {e.printStackTrace();}
vechicles.add(Road.this.name+ "_" + i);
}
}
});
/* 每隔一秒检查对应的灯是否为绿,是则放行一辆车 */
ScheduledExecutorService timer = Executors.newScheduledThreadPool(1);
timer.scheduleAtFixedRate(new Runnable()
{
publicvoid run(){
if(vechicles.size()>0){
boolean lighted =Lamp.valueOf(Road.this.name).isLighted();//内部类访问原则
if(lighted){
System.out.println(vechicles.remove(0)+ " is traversing !");
}
}
}
},
1,
1,
TimeUnit.SECONDS);
}
---------------------- android培训、java培训、期待与您交流! ----------------------