需求:模拟实现十字路口的交通灯,
1、信号灯忽略黄灯,只考虑红灯和绿灯;
2、直线、左转车辆受信号灯控制,右转车辆不受信号灯控制
3、南北向车辆与东西向车辆交替放行,同方向等待车辆应先放行直行车辆而后放行左转车辆。
十字路口的模拟图:
根据需求我们需要抽象的类有:信号灯、信号灯控制器、路。
从十字路口的模拟图,可以看出南和北的路线相对应、东和西的路线相对应,这样我们只要考虑两个方向上的信号灯就可以了。假设我们只考虑由南向北和由东向西方向上的信号灯。
1、先设计信号灯:首先考虑灯的属性,灯亮与否;灯当前在那个方向上;当前灯灭了后下一个灯该在哪个方向上;灯还需要用来控制当前灯的变化方法。
假如我们用普通类来设计这个灯,可能会设计成这样:
public class Lamp { private boolean lighted; private Lamp opposite; private Lamp next; public Lamp(Lamp opposite,Lamp next,boolean lighted){ this.opposite = opposite; this.next = next; this.lighted = lighted; } /** * 当前灯的状态 * @return */ public boolean isLighted(){ return lighted; } public void light(){ lighted = true; if(opposite != null){ opposite.light(); } } public Lamp back(){ lighted = false; if(opposite != null){ opposite.back(); } Lamp nextLamp = null; if(next != null){ next.light(); nextLamp = next; } return nextLamp; }}
若设计成这样,当我们在创建这个类的时候会发现这个类创建不出来,因为当创建A时需要先创建B和C,而创建B又需要先创建D等等,所有我们考虑用枚举来做。
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 Lamp(String opposite,String next,boolean lighted){ this.opposite = opposite; this.next = next; this.lighted = lighted; }
其他合上面的方法一样
}
灯设计好了,现在设计灯的控制器
2、设计信号灯的控制器:控制器主要作用是控制每隔多久灯变化一次。考虑到控制器肯能被多个路口调用,且在整个系统中又是独立的,故将其设计成单例。
public class LampContraller { private Lamp currLamp; private static LampContraller instance = new LampContraller(); private LampContraller(){ Lamp opposite = new Lamp(null,null,false); Lamp next = new Lamp(null,null,false); currLamp = new Lamp(opposite,next,false); currLamp.light(); } public static LampContraller getInstance(){ return instance; } public void contrallCode(){ ScheduledExecutorService timer = Executors.newScheduledThreadPool(1); timer.scheduleAtFixedRate( new Runnable(){ public void run(){ currLamp = currLamp.back(); } }, 10, 10, TimeUnit.SECONDS); }}接下来就剩下路的设计了
3、首先要考虑的是车是在路上的,所有需要有个存储车的空间,其次是这个路的名称;还有车辆到了当前路口和车辆离开当前路口的方法。代码如下:
public class Road { private List<String> cars = new ArrayList<String>(); private String roadName = ""; public Road(String name){ this.roadName = name; carOnRoad(); carMoveRoad(); } /** * 车到了路口 */ private void carOnRoad(){ Executors.newSingleThreadExecutor().execute(new Runnable(){ public void run(){ for(int i=1;i<1000;i++){ try { Thread.sleep((new Random().nextInt(10) + 1) * 1000); } catch (InterruptedException e) { e.printStackTrace(); } cars.add("车辆"+Road.this.roadName + "_" + i); System.out.println("车辆"+Road.this.roadName + "_" + i+"到了路上"); } } }); } /** * 车开走了 */ private void carMoveRoad(){ Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(new Runnable(){ public void run(){ if(cars.size() > 0){ boolean lampStatus = false; if(lampStatus){ System.out.println(cars.remove(0)+"离开了路上"); } } } }, 1, 1, TimeUnit.SECONDS); }}
好了设计完成。这里需要注意的是不要被方向给绕进去了,考虑使用枚举。