------- android培训、java培训、期待与您交流! ----------
模拟实现十字路口的交通灯管理系统逻辑,具体需求如下:
1.异步随机生成按照各个路线行驶的车辆。例如:由南向北的直行车辆,由西向南的右转车辆,由东向南的左转车辆。
2.信号灯只考虑红灯和绿灯,忽略黄灯
3.应考虑左转车辆控制信号灯,右转车辆不受信号灯控制
4.具体信号灯控制逻辑与现实生活逻辑相同,例如:南北向车辆与东西向车辆交替放行,通方向等待车辆应先放行直行车辆而后放行左转车辆
5.每辆车通过路口的时间为1秒
6.随机生成车辆时间间隔和红绿灯切换时间间隔可以设置
7.不要求实现GUI,只考虑系统逻辑实现
由上图分析可知,十字路口应受交通灯影响的汽车行驶车道(方向)为1、2、4、5、7、8、10、11共8个车道,就应该有对应的8个方向的信号灯。信号灯变绿的顺序是2和8,然后是1和7,然后是5和11,然后是10和4。
面向对象设计(OOD)就是根据项目需求进行面向对象分析(OOA),然后把项目中有哪些对象,对象中有哪些方法(行为)和字段(数据)搞清楚。面向对象设计要比面向对象编程(OOP)重要许多,面向对象设计做好了,面向对象编程只是照着设计图去完善细节。所有的设计模式(design pattern)都是面向对象设计经验。
OOD经验:谁拥有数据,谁就对外提供操作这些数据的方法。
例如:人在黑板上画圆,画圆的方法应该在圆对象中。
例如:列车司机紧急刹车,刹车的方法应该在列车对象中。
例如:售票员统计售货小票的金额,统计金额的方法应该在小票对象中。
例如:你把门关上了,关门的方法应该在门对象中。
例如:球从一根绳子的一端移动到了另一端,对象有两个球和绳子,移动应该是球对象的方法,移动的是位置,所以球对象应该还有一个位置属性,绳子对象应该有起点和终点属性,还应该有一个提供球移动下一位置的方法:代码如下:
class Rope{ Point start; Point end; public Rope(Point start,Point end) { this.start=start; this.end=end; } public Point nextPoint(Point currentPoint){ /*通过两点一线的数学公式可以计算出当前点的下一个点, * 这个细节不属于设计阶段要考虑的问题 * 如果当前点是终止点,则返回null, * 如果当前点不是线上的点,则抛出异常*/ } } class Ball{ Rope rope; Point currentPoint;//当前位置 public Ball(Rope rope,Point startPoint){ this.rope=rope; this.currentPoint=startPoint; } public void move(){ currentPoint=rope.nextPoint(currentPoint); System.out.println("小球移动到了"+currentPoint); } }例如:两块石头磨成一把石刀,石刀可以砍树,砍成木材,木材做成椅子。
StoneKnife=KnifeFactory.createKnife(stone);
Timber=StoneKnife.cut(Tree)
Chair=ChairFactory.makeChair(Timber);
来分析一下交通灯系统:初步设想一下都有哪些对象:红绿灯,车,车道。由于有8个红绿灯需要同步转换红绿,所以需要一个红绿灯控制系统。又由于本项目不要求体现车辆的整个移动过程,只是捕捉车辆穿过路口的过程,所以车不需要单独设计为一个对象,应该作为车道的一个集合属性。这样最终就有三个对象:红绿灯,红绿灯控制系统,车道。
首先分析红绿灯对象,一共有8个红绿灯,把右转弯方向也考虑成一个常绿的红绿灯,则一共有12个红绿灯,由于每个红绿灯控制的方向恒定保持不变,所以考虑用枚举实现红绿灯,里边包含12个枚举值。每个红绿灯枚举值包含三个属性,第一个是当前灯的颜色,第二个是对面灯的枚举值,第三个是下一个要亮的灯的枚举值。
import java.util.ArrayList; 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 ArrayList<String> automobiles=new ArrayList<String>(); private String name=null;//路的名字 //在构造函数中使路‘活’起来,既车辆随机进入此车道,并根据本车道的交通灯通过路口 public Road(String name){ this.name=name; //初始化道路上的车辆 ExecutorService pool= Executors.newSingleThreadExecutor(); pool.execute(new Runnable() { public void run() { for (int i = 1; i < 1000; i++) { try { //本线程随机休息1到10秒 Thread.sleep((new Random().nextInt(10)+1)*1000); } catch (InterruptedException e) {} automobiles.add(Road.this.name+"车道的第"+i+"辆车"); System.out.println(Road.this.name+"车道的第"+i+"辆车进入"+Road.this.name+"车道"); } } }); //如果一辆车看见自己的灯是绿的,则车通过 ScheduledExecutorService timer=Executors.newScheduledThreadPool(1); timer.scheduleAtFixedRate(new Runnable() { public void run() { if (automobiles.size()>0) { boolean lampState=true; if (lampState==true) { System.out.println(automobiles.remove(0)+"离开"+Road.this.name+"车道"); } } } }, 1, 1,TimeUnit.SECONDS); } }
public enum Lamp { S1(false,"N7","E5"),S2(false,"N8","S1"),S3(true,null,null), E4(false,"W10","S8"),E5(false,"W11","E4"),E6(true,null,null), N7(false,"S1","W11"),N8(false,"S2","N7"),N9(true,null,null), W10(false,"E4","S2"),W11(false,"E5","W10"),W12(true,null,null); //表示当前交通的状态,是否是绿的,true为绿 private boolean isGreen; //表示相反方向交通灯的名字 private String opposite; //表示下一个要亮起的交通灯的名字 private String next; //构造方法初始化各个成员变量 Lamp(boolean isGreen,String opposite,String next){ this.isGreen=isGreen; this.opposite=opposite; this.next=next; } //获取当前交通灯状态 public boolean getIsGreen(){ return isGreen; } //使当前交通灯变绿 public void turnGreen(){ //将当前交通灯变绿 this.isGreen=true; //将对面交通灯也变绿 Lamp oppo=Lamp.valueOf(opposite); if (oppo.isGreen==false) { oppo.turnGreen(); } } //使当前交通灯变红 public void turnRed(){ //将当前交通变红 this.isGreen=false; //将对面交通灯也变红 Lamp oppo=Lamp.valueOf(opposite); if (oppo.isGreen==true) { oppo.turnGreen(); } //将下一个交通灯变绿 Lamp nextLight=Lamp.valueOf(next); if (nextLight.isGreen==false) { nextLight.turnGreen(); } } }
// boolean lampState=true; boolean lampState=Lamp.valueOf(Road.this.name).getIsGreen();
import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; public class LampController { private Lamp currentLamp; public LampController(Lamp inialLamp){ currentLamp=inialLamp; } public void start(){ currentLamp.turnGreen(); ScheduledExecutorService timer= Executors.newScheduledThreadPool(1); timer.scheduleAtFixedRate(new Runnable() { public void run() { Lamp next= currentLamp.turnRed(); currentLamp=next; } },10,10,TimeUnit.SECONDS); } }
public class TrafficeDemo { public static void main(String[] args) { String[] roads=new String[]{ "S1","S2","S3", "E4","E5","E6", "N7","N8","N9", "W10","W11","W12" }; for (int i = 0; i < roads.length; i++) { new Road(roads[i]); } LampController controller=new LampController(Lamp.S2); controller.start(); } }然后修改Lamp枚举的turnRed方法,使它可以返回下一个交通的Lamp对象
//使当前交通灯变红 public Lamp turnRed(){ //将当前交通变红 this.isGreen=false; //将对面交通灯也变红 Lamp oppo=Lamp.valueOf(opposite); if (oppo.isGreen==true) { oppo.turnRed(); } //将下一个交通灯变绿 Lamp nextLight=Lamp.valueOf(next); if (nextLight.isGreen==false) { nextLight.turnGreen(); } return nextLight; }然后启动程序观察运行结果:
S2的交通灯变绿了 N8的交通灯变绿了 S3车道的第1辆车进入S3车道 N8车道的第1辆车进入N8车道 S3车道的第1辆车离开S3车道 N8车道的第1辆车离开N8车道 W10车道的第1辆车进入W10车道 E4车道的第1辆车进入E4车道 N7车道的第1辆车进入N7车道 W12车道的第1辆车进入W12车道 W12车道的第1辆车离开W12车道 N7车道的第2辆车进入N7车道 E6车道的第1辆车进入E6车道 E6车道的第1辆车离开E6车道 S1车道的第1辆车进入S1车道 N9车道的第1辆车进入N9车道 N9车道的第1辆车离开N9车道 S3车道的第2辆车进入S3车道 S2车道的第1辆车进入S2车道 S3车道的第2辆车离开S3车道 N8车道的第2辆车进入N8车道 N8车道的第2辆车离开N8车道 S2车道的第1辆车离开S2车道 E5车道的第1辆车进入E5车道 S1车道的第2辆车进入S1车道 W11车道的第1辆车进入W11车道 W12车道的第2辆车进入W12车道 S3车道的第3辆车进入S3车道 S3车道的第3辆车离开S3车道 E6车道的第2辆车进入E6车道 W11车道的第2辆车进入W11车道 W12车道的第2辆车离开W12车道 E6车道的第2辆车离开E6车道 N7的交通灯变绿了 S1的交通灯变绿了 S1车道的第1辆车离开S1车道 N7车道的第1辆车离开N7车道 N7车道的第3辆车进入N7车道 S1车道的第2辆车离开S1车道 W10车道的第2辆车进入W10车道 N7车道的第2辆车离开N7车道 E4车道的第2辆车进入E4车道 N7车道的第3辆车离开N7车道 W11车道的第3辆车进入W11车道每个车道的车辆数单独计算,这样可以回避多线程安全的问题,交通灯依次变绿,右转弯车辆不受交通灯影响。如果改为整个十字路口计算车辆总数和车的次序,则会出现同一辆车进入两个车道的问题。