需求:
模拟实现十字路口的交通灯管理系统逻辑,具体需求如下:
1.异步随机生成按照各个路线行驶的车辆。
例如:
由南向而来去往北向的车辆 ---- 直行车辆
由西向而来去往南向的车辆 ---- 右转车辆
由东向而来去往南向的车辆 ---- 左转车辆
。。。
2.信号灯忽略黄灯,只考虑红灯和绿灯。
3.应考虑左转车辆控制信号灯,右转车辆不受信号灯控制。
4.具体信号灯控制逻辑与现实生活中普通交通灯控制逻辑相同,不考虑特殊情况下的控制逻辑。
注:南北向车辆与东西向车辆交替放行,同方向等待车辆应先放行直行车辆而后放行左转车辆。
5.每辆车通过路口时间为1秒(提示:可通过线程Sleep的方式模拟)。
6.随机生成车辆时间间隔以及红绿灯交换时间间隔自定,可以设置。
7.不要求实现GUI,只考虑系统逻辑实现,可通过Log方式展现程序运行结果。
面向对象的分析与设计:
1.车的通行方式:先由南北通向直行,直行以后是南北通向的左转弯的车辆通行。
接下来是东西方向的直行车辆,直行后是东西通向的左转弯车辆。
之后再次是南北直行车辆,如此循环交替行驶。
2.设想一下有哪些对象:红绿灯,红绿灯的控制系统,汽车,路。汽车看到自己所在的路线对应的灯
绿了就穿过路口吗?不是,还需要看其前面是否有车,该问那个对象呢?该问路,路中存数这车辆的
集合,显然路上就应该有增加车辆和减少车辆的方法了。回顾题目,我们这里并不要体现车辆移动的
过程,只是捕捉出车辆穿过路口的过程,也就是捕捉路上减少一辆车的过程,所以,这个车并不需要
单独设计成一个对象,用一个字符串表示就可以了。
面向对象设计把握一个重要的经验:谁拥有数据,谁就对外提供操作这些数据的方法。在牢牢掌握几
个典型的案例就可以了:人在黑板上花园,列车司机紧急刹车,售货员统计收货小票的金额。
两块石头磨成一把石刀,用石刀把树砍成木材,用木材做成椅子。实现模拟:
StoneKnife = KnifeFactory.createKnife(stone);石头工厂把石头变成石刀。
Mood = StoneKnife.cut(tree);石刀把树砍成木材
Chair = ChairFactory.makeChair(mood);椅子工厂把木材做成椅子。
为什么不把做椅子的方法分配给木材呢?
因为,木材把自己变成椅子后,木材对象就不存在了。把自己变没了。不科学。
代码如下:
Road类:
public class Road { //每条路线
private String name = null; //路的名字
List<String> verchicles = new ArrayList<String>(); //车
public Road(String name){
this.name = name;
//为了避免构造方法出现难产状况。调用此构造方法时,创建线程池,并创建一个产生车的线程。
Executors.newSingleThreadExecutor().execute(new Runnable(){
public void run() {
//开线程产生1000两车,并给名字(路名+车辆的序号)
for(int i=1;i<=1000;i++){
try {//休息,1到10秒内随机出现一辆车
Thread.sleep((new Random().nextInt(10)+1)*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
verchicles.add(Road.this.name+"_"+i);
}
}
});
//定时器
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
new Runnable(){
public void run(){
if(verchicles.size()>0){//判断是否有排队的车辆
//获取当前车辆所在路线的灯是否为绿色。
boolean lighted = Lamp.valueOf(Road.this.name).isLighted();
if(lighted){//判断,如果为绿灯。从集合中移走已经路过路口的车,并打印
String verchicle = verchicles.remove(0);
System.out.println(verchicle+" is travering");
}
}
}
},
1,
1,
TimeUnit.SECONDS);
}
}
Lamp类:
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 String opposite;
private boolean lighted;
private String next;
private Lamp(){
};
//枚举的构造方法必须为私有,opposite:与之对应的灯,next:下一个要亮的灯,lighted:灯的初始状态
private Lamp(String opposite,String next,boolean lighted){
this.opposite= opposite;
this.next = next;
this.lighted = lighted;
}
public boolean isLighted(){
return this.lighted;
}
public void light(){
System.out.println(name()+" is green.下面可以看到六个方向的车辆运行");
this.lighted= true;
if(this.opposite!=null){
//lamp.valueOf(str)将字符创转换为相应的枚举类型。
Lamp.valueOf(opposite).light();
}
}
//此灯变黑的同时,要将下一个灯点亮。并且返回下一个灯的对象nextLamp,为了方便下一次调用此方法。
public Lamp blackOut(){
this.lighted = false;
if(this.opposite!=null){
Lamp.valueOf(opposite).blackOut();
System.out.println("aaa");
}
Lamp nextLamp =null;
if(this.next!=null){
nextLamp = Lamp.valueOf(this.next);
System.out.println("绿灯从"+name()+"切换为------->"+next);
nextLamp.light();
}
return nextLamp;
}
}
LampController类:
//实现灯的按时亮灭控制
public class LampController {
private Lamp currentLamp;
public LampController(){
currentLamp = Lamp.S2N;
currentLamp.light();
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
new Runnable(){
public void run(){
currentLamp = currentLamp.blackOut();
}
},
10,
10,
TimeUnit.SECONDS);
}
}
MainClass类:
public class MainClass {
public static void main(String[] args) {
String[] directions = new String[]{"N2S","N2E","W2E","W2N",
"S2N","S2W","E2W","E2S","N2W","W2S","S2E","E2N"};
//创建12个路对象
for(int i =0;i<directions.length; i++){
//因为路内部有定时器和创建车辆的线程,所以路对象不会马上被GC回收,
//只有等1000辆车都通过后对象才会失效。
new Road(directions[i]);
}
//创建一个灯控制器。
new LampController();
}
}
定时器:
scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)
按照固定的频率重复一件事
参数:command:要执行的事务,实现Runnable接口,和run方法。run方法中存放要执行的事务;
参数:initialDelay:第一次延迟多少时间以后执行command事务;
参数:period:以后每次循环的周期;
参数:unit:定义时间单位;