今天看了张孝祥老师的“交通灯管理系统”的题目和解决方案,尝试着再自己分析这个场景,实现不一定很好,权当学习了。
首先提取下这个问题的关键要素:交通灯,路,车。三者的一种关系是车可以认为是路的“元素”,车的通过和增加都是由路负责管理的。而每一个十字路口的放行与否,都是通过交通灯控制的。路和灯应该是归属的关系,一个十字路口“拥有”一个交通灯系统。
所以我们抽象交通灯这个类,因为向右是永远放行的,所以我们可以忽略向右的这条线路,而相反方向的灯的变化是完全相同的,所以可以抽象为一个管理系统,这样其实一个路口的交通等的状态就只有4种了,而且这四种同一时刻只有一个是放行的状态。
用枚举实现交通灯:
1 package traffic; 2 3 public enum Lamp { 4 NSStraight, NSTurn, EWStraight, EWTurn; 5 6 private boolean green = false; 7 8 public boolean isGreen() { 9 return green; 10 } 11 12 public void lighteOn() { 13 this.green = true; 14 System.out.println(this.toString()); 15 } 16 public void lightOff(){ 17 this.green = false; 18 } 19 20 Lamp nextLamp() { 21 switch (this) { 22 case NSStraight: 23 lightOff(); 24 NSTurn.lighteOn(); 25 return NSTurn; 26 case NSTurn: 27 lightOff(); 28 EWStraight.lighteOn(); 29 return EWStraight; 30 case EWStraight: 31 lightOff(); 32 EWTurn.lighteOn(); 33 return EWTurn; 34 case EWTurn: 35 lightOff(); 36 NSStraight.lighteOn(); 37 return NSStraight; 38 } 39 return null; 40 } 41 @Override 42 public String toString(){ 43 switch (this) { 44 case NSStraight: 45 return "----------南北方向直行"; 46 case NSTurn: 47 return "----------南北方向左转"; 48 case EWStraight: 49 return "----------东西方向直行"; 50 case EWTurn: 51 return "----------东西方向左转"; 52 } 53 return null; 54 55 } 56 }
交通灯的轮换相对来说比较独立,和路的耦合不算大,每个路口可以独立于路配备一个交通灯,这里先用线程实现模拟交通灯的切换规则:
1 package traffic; 2 3 public class LampControl implements Runnable{ 4 Lamp NSStraight = Lamp.NSStraight; 5 Lamp NSTurn = Lamp.NSTurn; 6 Lamp EWStraight = Lamp.EWStraight; 7 Lamp EWTurn = Lamp.EWTurn; 8 9 Lamp currentLamp = NSStraight; 10 11 public Lamp getCurrentLamp() { 12 return currentLamp; 13 } 14 15 int StraightTime = 10000;//ms 16 int TurnTime = 10000; 17 @Override 18 public void run() { 19 currentLamp.lighteOn(); 20 while(true){ 21 try { 22 Thread.sleep(StraightTime); 23 currentLamp = currentLamp.nextLamp(); 24 Thread.sleep(TurnTime); 25 currentLamp = currentLamp.nextLamp(); 26 Thread.sleep(StraightTime); 27 currentLamp = currentLamp.nextLamp(); 28 Thread.sleep(TurnTime); 29 currentLamp = currentLamp.nextLamp(); 30 31 } catch (InterruptedException e) { 32 e.printStackTrace(); 33 } 34 } 35 36 37 } 38 39 }
这样在主函数中可以通过独立的线程模拟单独的交通灯切换功能。
接下来模拟十字路口的车辆过往的展示,一个十字路口有一个交通灯系统,抛开向右自由行驶的路线,有8条行车路线,每条路线用一个集合存放这条路线上的车,适当的时候放行。
1 package traffic; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 6 public enum SingleRoad { 7 NSRoad, SNRoad, NSLRoad, SNLRoad, EWRoad, WERoad, EWLRoad, WELRoad; 8 int num = 1; 9 List<Integer> list = new ArrayList<Integer>(); 10 11 public void addCar() { 12 this.list.add(num++); 13 System.out.println(this.toString()+": "+num + "号车正在等待"); 14 } 15 16 public void passCar() { 17 if(this.list.size()>0){ 18 Integer i = this.list.remove(0); 19 System.out.println(this.toString()+": "+ i + "号车正在过马路"); 20 } 21 } 22 23 @Override 24 public String toString() { 25 switch (this) { 26 case NSRoad: 27 return "北向南"; 28 case SNRoad: 29 return "南向北"; 30 case NSLRoad: 31 return "北向南左"; 32 case SNLRoad: 33 return "南向北左"; 34 case EWRoad: 35 return "东向西"; 36 case WERoad: 37 return "西向东"; 38 case EWLRoad: 39 return "东向西左"; 40 case WELRoad: 41 return "西向东左"; 42 } 43 return null; 44 } 45 46 }
在创建一个Road类管理一个十字路口的情形,随机的往每条线路上增加车辆并等待,当这条线路的控制灯亮的时候,放行这条线路上的车。
1 package traffic; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 import java.util.Random; 6 7 public class Road implements Runnable { 8 LampControl lc = new LampControl(); 9 List<SingleRoad> listRoads = new ArrayList<SingleRoad>(); 10 SingleRoad NSRoad = SingleRoad.NSRoad; 11 SingleRoad SNRoad = SingleRoad.SNRoad; 12 SingleRoad NSLRoad = SingleRoad.NSLRoad; 13 SingleRoad SNLRoad = SingleRoad.SNLRoad; 14 SingleRoad EWRoad = SingleRoad.EWRoad; 15 SingleRoad WERoad = SingleRoad.WERoad; 16 SingleRoad EWLRoad = SingleRoad.EWLRoad; 17 SingleRoad WELRoad = SingleRoad.WELRoad; 18 19 public Road(LampControl lc) { 20 this.lc = lc; 21 listRoads.add(NSRoad); 22 listRoads.add(NSLRoad); 23 listRoads.add(SNRoad); 24 listRoads.add(SNLRoad); 25 listRoads.add(EWLRoad); 26 listRoads.add(EWRoad); 27 listRoads.add(WELRoad); 28 listRoads.add(WERoad); 29 } 30 31 void method(){ 32 while(true){ 33 Lamp l = lc.getCurrentLamp(); 34 switch (l) { 35 case NSStraight: 36 NSRoad.passCar(); 37 SNRoad.passCar(); 38 passTime(); 39 break; 40 case NSTurn: 41 NSLRoad.passCar(); 42 SNLRoad.passCar(); 43 passTime(); 44 break; 45 case EWStraight: 46 EWRoad.passCar(); 47 WERoad.passCar(); 48 passTime(); 49 break; 50 case EWTurn: 51 EWLRoad.passCar(); 52 WELRoad.passCar(); 53 passTime(); 54 break; 55 } 56 } 57 58 } 59 60 private void passTime(){ 61 try { 62 //一秒过一辆 63 Thread.sleep(1000); 64 } catch (InterruptedException e) { 65 e.printStackTrace(); 66 } 67 } 68 69 @Override 70 public void run() { 71 while (true) { 72 try { 73 //1--3秒随机添加一辆车 74 Thread.sleep((new Random().nextInt(3) + 1) * 1000); 75 } catch (InterruptedException e) { 76 e.printStackTrace(); 77 } 78 int index = new Random().nextInt(8); 79 SingleRoad sr = listRoads.get(index); 80 sr.addCar(); 81 } 82 83 } 84 85 }
这样当我们实际运行的时候就有三个线程了,一个线程专门负责灯的转换,一个线程专门负责车的添加,一个线程负责灯亮的时候车的放行。
1 public static void main(String[] args) { 2 LampControl lc1 = new LampControl(); 3 Road road = new Road(lc1); 4 new Thread(lc1).start(); 5 new Thread(road).start(); 6 road.method(); 7 }
有了张老师对整体思路的分析,自己沿着老师的思维走了一遍,收货颇多。