---------------------- ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------
模拟实现十字路口的交通灯管理系统逻辑,具体需求如下:
-
异步随机生成按照各个路线行驶的车辆
-
由南向被而来往北向的车辆....直行车辆 -
由西而来去往南向的车辆....右转车辆 -
由东向而来去往南向的车辆....左转车辆
......
-
信号灯忽略黄灯,只考虑红灯和绿灯。
-
应该考虑左转车辆控制信号灯,右转车辆部不信号灯控制。
-
具体信号灯控制逻辑与现实生活中普通交通灯控制逻辑相同,不考虑特殊情况下的控制逻辑。
-
每辆车通过路口时间为1秒(提示:可通过线程Sleep的方式模拟)。 -
随机生成车辆时间间隔以及红绿灯交换时间间隔自定,可以设置。 -
不要求实现GUI,只考虑系统逻辑实现,可通过Log方式展示程序运行结果。
一、路况分析图
通过画图的方式,分析一下十字路口车辆行驶的规律。看下图,
以向南的公路为例,车辆可以向3个方向前进(2表示to):S2W,S2N,S2E。每个方向的公路都有3个前进方向,总共有12条方向。但是仔细分析就会发现,S2N和N2S其实是同一车流,只能由北向南开或者只能由南向北都是不可能的。所以,严格意义上,总共是4种车流:
1.
2.
3.
4.
下图是一个真实的十字路口的交通灯,也是目前最常用的形式。有3个灯组成,每个灯都可以独立现实红、黄、绿,并指示相应的方向:左转、右转、直行。
按照需求分析如下:
1. 按照需要,只有红灯和绿灯,不考虑黄灯。也可以理解为亮(绿灯)与不亮(红灯)。
2. 由于提示不用考虑右转,所以应该假设右转灯始终为绿色(亮灯)。
3. 现实生活中,某个方向上,例如南北,总是先直行然后左转,左转完毕后东西方向上的直行和左转。如此循环执行。
4. 通过左转灯和直行灯的不同组合开控制车流,每辆车只要看自己面前的灯即可,不用考虑其他方向的灯。不考虑汽车想要行驶的方向,汽车受灯控制:红灯停绿灯行。
5. 每辆车通过的时间为1秒,也就是说,绿灯如果亮5秒,会有5辆车通过。
三、面向对象分析和设计
可能出现的对象有:交通灯、交通灯控制器、汽车和路。
汽车看到灯变绿后,不能马上前进,还要确定前面没有汽车才能前进,也就是只有第一辆车才能前进。如何确定前面是否有车?应该询问路,路上储存车的集合,也有增加和减少汽车的方法。本题关注的不是车辆移动过程,而是车辆通过路口的过程,所以车辆不需要单独设计成对象,只要将其用字符串表示,即“1号车通过”、“2号车通过”。这里的路,也可以理解为车流。
这也是面向对象编程的经验:谁拥有数据,谁就要对外提供操作数据的方法。例如,人在黑 板上画圆,画圆的动作是由黑板做出的,人只是在调用方法。
综合上面的分析,只需要3个类:交通灯(Lamp类)、控制系统(LampController类)和路(Road类)。
Road类的设计:
每条路线内都有一个集合,元素为车辆。
绿灯时,每秒减少一辆车;红灯时,随机增加车辆。
因为有12条路线,需要有12个Road对象。
每条路线每秒都要检查对应的灯是否为绿(亮),是的话即移除集合中的第一辆车,表示汽车通过路口。
Lamp类的设计:
每个灯在一段时间内只有一个状态:绿或红,每个灯都有变绿或者变红的方法,并且可以返回下一个灯。因为只有2个状态,可以使用布尔值的真假表示:真(绿)、假(红)。
因为有12条线路,所有有12个交通灯。不考虑右转,所以4个右转灯始终是绿灯,车辆可以随时右转。
除了右转,还有8个方向,考虑对面而行可以合为一个方向,实际只有4个方向的车流。实际编程时,每个方向的车流只需要使用一个灯表示即可,所以只需要4个灯来控制车流。这4个灯会依次变绿。按照真实情况,每个灯变绿时,对面方向的灯也会变绿,因为他们是一一对应的,变绿后汽车通过路口;主灯变红后,也会使得对面的灯变红。
每个灯变红后,会将下一个灯变绿、对面的灯变动,这就需要2个成员变量:对面的灯和下一个灯;还需要记住自己的状态,是否为绿,所以共有3个成员变量。
LampController类的设计:
需要一个监视器,随时监视本灯的状态,时间一到就将当前的灯变红,并监视下一个灯,循环执行。
(1)路
package com.isoftstone.interview.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 vehicles=new ArrayList();
//初始化路的名字
private String nameString=null;
public Road(String name){
this.name=name;
//创建线程池
ExecutorService pool=Executors.newSingleThreadExecutor();
//创建实现类
pool.execute(new Runnable(){
public void run() {
for (int i = 1; i < 10000; i++) {
try {
Thread.sleep((new Random().nextInt(10)+1)*1000);//随机产生1-10秒的随机数
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//内部类调用外部类的成员变量
vehicles.add(Road.this.nameString+"_"+i);
}
}
});
//定义一个定时器
ScheduledExecutorService timer=Executors.newScheduledThreadPool(1);
timer.scheduleAtFixedRate(
new Runnable(){
public void run() {
if(vehicles.size()>0){
boolean lighted=Lamp.valueOf(Road.this.nameString).isLighted();
if (lighted) {
System.out.println(vehicles.remove(0)+"is traversing");
}
}
}
},
1,
1,
TimeUnit.SECONDS
);
}
}
(2)灯
package com.isoftstone.interview.traffic;
public enum Lamp {
//2代表to,E代表东 S代表南,N代表北,W代表西,
//设置灯的变动,车的走向
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 Lamp(String opposite,String next,boolean lighted) { //构造方法的三个参数分别为对应灯,下一个灯,灯的状态
this.oppositeLamp=opposite;
this.nextString=next;
this.lighted=lighted;
}
//无参构造方法
private Lamp () {
}
//灯的状态
private boolean lighted;
//对面的灯
private String oppositeLamp;
//下一个灯
private String nextString;
//get方法返回灯的状态
public boolean isLighted() {
return lighted;
}
//灯亮
public void light() {
this.lighted=true;
if (oppositeLamp!=null) {
Lamp.valueOf(oppositeLamp).light();//返回枚举对象
}
System.out.println(name()+"lamp is green .下面可以看到六个方向的汽车穿过");
}
//灯灭并返回下一个灯
public Lamp blackOut() {
this.lighted=false;
if (oppositeLamp!=null) {
Lamp.valueOf(oppositeLamp).blackOut();//返回枚举对象
}
Lamp nextLamp=null;
if (nextString!=null) {
nextLamp=Lamp.valueOf(nextString);
System.out.println("绿灯从"+name()+"--->切换为"+nextString);
nextLamp.light();
}
return nextLamp;
}
}
(3)灯的监视器
package com.isoftstone.interview.traffic;
public LampController(){
//刚开始让由南向北的灯变绿;
currentLamp = Lamp.S2N;
currentLamp.light();
/*每隔10秒将当前绿灯变为红灯,并让下一个方向的灯变绿*/
ScheduledExecutorService timer = Executors.newScheduledThreadPool(1);
timer.scheduleAtFixedRate(
new Runnable(){
public void run(){
System.out.println("来啊");
currentLamp = currentLamp.blackOut();
}
},
10,
10,
TimeUnit.SECONDS);
}
}
(4)设计一个MainClass类来对当前程序进行测试:
package com.isoftstone.interview.traffic;
public class MainClass {
public static void main(String[] args) {
//用for循环创建出代表12条路线的对象
String [] directions = new String[]{
"S2N","S2W","E2W","E2S","N2S","N2E","W2E","W2N","S2E","E2N","N2W","W2S"
};
---------------------- ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------