交通灯管理系统项目需求:
模拟实现十字路口的交通灯系统逻辑,具体需求如下:
异步随机生成按照各个路线形式的车辆。
由南向而来去往北向的车辆---直行车辆
由西向而来去往南向的车辆---右转车辆
由东向而来去往南向的车辆---左转车辆
......
信号灯忽略黄灯,只考虑红灯和绿灯。
应考虑左转车辆控制信号灯,右转车辆不受信号灯控制。
具体信号灯控制逻辑与现实生活中普通交通灯扩至逻辑相同,不考虑特殊状况下的控制逻辑。
注:南北向车辆与东西向车辆交替放行,同方向等待车辆应先放行直线车辆而
后放行左转车辆。
每辆车通过路口时间为1秒(提示:可通过线程sleep的方式模拟),随机生成车辆时间间隔以及红绿灯交换时间间隔自定,可以设置。
不要求实现GUI,值考虑系统逻辑实现,可通过log方式展现程序运行结果。
线路数量分析:
总共有12条线路,为了统一编程模型,可以假设每条路线上都有一个红绿灯对其进行控制,右转弯的4条线路的控制灯可以假设为常绿状态,另
外其它的8条线路是两两成对的,可以归为4组,所以,程序只需要考虑途中标注了数字号的控制灯切换顺序,这4条路线相反的路线的控制灯
随着4条线路切换,不必考虑其它。
线路对应分析(相对方向亮) | |||
①南-->北
| ↑ | ⑤北-->南 | ↓ |
②南-->西
| ↖ | ⑥北-->东 | ↘ |
③东-->西
| ← | ⑦西-->东 | → |
④东-->南
| ↙ | ⑧西-->北 | ↗ |
面向对象的分析与设计:
(***补充:面向对象设计把握一个重要的经验——谁拥有数据,谁就对外提供操作这些数据的方法)
详细设计:(工程名traffic)
一、类
1、Lamp枚举类,灯
1.1 每个枚举元素各表示一个方向的控制灯
S2N("N2S","S2W",false),
S2W("N2E","E2W",false),
E2W("W2E","E2S",false),
E2S("W2N","S2N",false),
1.2 下面元素表示与上面的元素的相反方向的灯,它们的“相反方向灯”和“下一个灯”应忽略不计!
N2S(null,null,false),
N2E(null,null,false),
W2E(null,null,false),
W2N(null,null,false),
1.3 由南向东和由西向北等右拐弯的灯不受红绿灯的控制,所以,可以假想它们总是绿灯
S2E(null,null,true),
E2N(null,null,true),
N2W(null,null,true),
W2S(null,null,true);
2、控制系统LampController
2.1获取当前等的变量
2.2获取一定时器,时间到,当前等转为红灯,并且下一个方向的等转为绿灯
3、路Road
二.部分所需类以及方法整理:
1
ExecutorService pool = Executors.newScheduledThreadPool(1);
创建一个线程池,-------------线程池(线程数)
2
Road.this.name
//第一种解决方案:内部类访问外部类成员变量,在外部类名前加final
//返回外部类的成员变量,为了避免与自己内部类的名字打架,所以:Road.this.name
3
new Random().nextInt(10)
//返回0~9的随机数
4
ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit)
//创建并执行在给定延迟后启用的一次性操作。
//(线程,推迟时间,推迟时间单位)
5
ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)
//创建并执行开始时间,然后过了多少秒之后继续干,再过多少秒再干, 再过多少秒再干, 再过多少秒再干......
//(线程,过多少秒之后去做,然后过多少秒再去干,时间单位)
6
TimeUnit.SECENDS
//时间单位.事件类型
7
valueOf(Class<T> enumType, String name)
返回带指定名称的指定枚举类型的枚举常量。
代码实现:
-----------------Road.java----------------------


1 package cn.itcast.interview.traffic; 2 //马路 3 import java.util.ArrayList; 4 import java.util.List; 5 import java.util.Random; 6 import java.util.concurrent.ExecutorService; 7 import java.util.concurrent.Executors; 8 import java.util.concurrent.ScheduledExecutorService; 9 import java.util.concurrent.TimeUnit; 10 11 public class Road { 12 //车的集合 13 private List<String> vechicles = new ArrayList<String>();//为了面向接口编程,所以是List集合 14 15 private String name=null; 16 //每条路线的名字 17 public Road(String name)//内部类访问外部类,想访问外部类的局部变量,外部类必须加final(final String name) 18 { 19 this.name = name; 20 //新建一个线程,用于添加汽车 21 //newScheduledThreadPool线程池(线程数) 22 ExecutorService pool= Executors.newScheduledThreadPool(1); 23 24 //创建一个线程,定隔多少秒进行休息 25 pool.execute(new Runnable()//执行池执行,new 了一个Runnable()实现对象 26 { 27 public void run() 28 { 29 for(int i =1;i<1000;i++)//产生999辆车 30 { 31 try { 32 Thread.sleep((new Random().nextInt(10)+1)*1000);//返回0~9的随机数,再加一,就可以是1~10秒 33 } catch (InterruptedException e) { 34 e.printStackTrace(); 35 } 36 vechicles.add(Road.this.name+"_"+i);//返回外部类的成员变量,为了避免与自己内部类的名字打架,所以:Road.this.name 37 } 38 } 39 }); 40 41 //定时器 42 ScheduledExecutorService timer = Executors.newScheduledThreadPool(1); 43 44 //循环定时器 45 timer.scheduleAtFixedRate(new Runnable(){ 46 public void run() 47 {//首先检查是否有车 48 if(vechicles.size()>0) 49 { 50 /*定义变量,之后就是在这里修改的..修改去检查这个灯 51 boolean lighted = true; 52 检查自己的灯,name为自己路线的名字,然后Lamp.valueOf(Road.this.name)获取自己路线的名字, 53 把自己的名字传过去,就获得了自己的灯*/ 54 boolean lighted = Lamp.valueOf(Road.this.name).isLighted(); 55 56 if(lighted) 57 //假如灯是绿的 58 System.out.println(vechicles.remove(0)+"is traversing !"); 59 } 60 } 61 }, 62 1,//开始时间 63 1,//循环时间 64 TimeUnit.SECONDS);//时间单位 65 } 66 }
-----------------Lamp.java----------------------


1 package cn.itcast.interview.traffic; 2 //灯 3 4 public enum Lamp { 5 //首先定义12个方向变量 6 //这四个是进行控制的 7 S2N("N2S","S2W",false),S2W("N2E","E2W",false),E2W("W2E","E2S",false),E2S("W2N","S2N",false), 8 9 //这四个的变量是随着上面而变的 10 N2S(null,null,false),N2E(null,null,false),W2E(null,null,false),W2N(null,null,false), 11 12 //下面的四个是长亮的 13 S2E(null,null,true),E2N(null,null,true),N2W(null,null,true),W2S(null,null,true); 14 15 private Lamp(String opposite,String next,boolean lighted)小提示:枚举的构造方法必须是私有的 16 { 17 this.opposite = opposite; 18 this.next = next; 19 this.lighted = lighted; 20 } 21 private Lamp()//不带参数的构造方法,为了让空值的家伙们不报错,因为有的没有对应的灯 22 { 23 24 } 25 26 27 //灯是否是亮的变量 28 private boolean lighted; 29 //对应的灯 30 private String opposite; 31 //定义下一个灯 32 private String next; 33 34 35 //亮的为绿,灭的为红,首先默认的为亮的 36 public boolean isLighted() 37 { 38 return lighted; 39 } 40 41 //变绿 42 public void light() 43 { 44 this.lighted = true; 45 //判断一下是否有对应的灯,有对应的灯,然后再变亮 46 if(opposite !=null) 47 { 48 Lamp.valueOf(opposite).light();//传递对应灯的字符串,然后valueOf(), 49 //valueOf()返回带指定名称的指定枚举类型的枚举常量。 50 } 51 52 //测试用 53 System.out.println(name()+"lamp is green.下面共有6个方向的车穿过..."); 54 } 55 //熄灯..变红 56 public Lamp blackOut() 57 { 58 this.lighted = false; 59 if(opposite !=null) 60 { 61 Lamp.valueOf(opposite).blackOut();//传递对应灯的字符串,然后valueOf(), 62 //valueOf()返回带指定名称的指定枚举类型的枚举常量。 63 } 64 65 Lamp nextLamp = null; 66 67 //如果有下一个灯,那么让下一个灯变绿,下一个等变绿之后,还会返回下一个变绿的灯 68 if(next !=null) 69 { 70 nextLamp = Lamp.valueOf(next); 71 72 //测试用 73 System.out.println("绿灯从"+name()+"-------->切换为"+next); 74 75 Lamp.valueOf(next).light(); 76 77 } 78 return nextLamp; 79 } 80 }
-----------LampController.java-----------------


1 package cn.itcast.interview.traffic; 2 3 import java.util.concurrent.Executors; 4 import java.util.concurrent.ScheduledExecutorService; 5 import java.util.concurrent.TimeUnit; 6 7 //灯的控制器 8 public class LampController { 9 //当前的灯 10 private Lamp currentLamp; 11 12 //构造方法 13 public LampController() 14 { 15 //指定第一个灯并且当前的灯为绿的 16 currentLamp = Lamp.S2N; 17 currentLamp.light(); 18 19 //定义一个定时器,过一段时间,让灯变色 20 ScheduledExecutorService timer = Executors.newScheduledThreadPool(1); 21 timer.scheduleAtFixedRate( 22 new Runnable() 23 { 24 public void run() 25 { 26 currentLamp = currentLamp.blackOut();//当前灯变黑 27 } 28 }, 29 10, 30 10, 31 TimeUnit.SECONDS); 32 33 } 34 }
---------------MainClass.java-------------------


1 package cn.itcast.interview.traffic; 2 /** 3 * 4 * @author Chen_zyan 5 * 6 */ 7 public class MainClass { 8 /** 9 * @param args 10 */ 11 public static void main(String[] args) 12 { 13 //创建一个数组,将这12个方向存入 14 String[] directions = new String[]{ 15 "S2N","S2W","E2W","E2S", 16 "N2S","N2E","W2E","W2N", 17 "S2E","E2N","N2W","W2S" 18 }; 19 20 for(int i =0;i<directions.length;i++) 21 { 22 new Road(directions[i]); 23 } 24 new LampController();//控制器 25 26 } 27 }