-----Java培训、Android培训、iOS培训、.Net培训、期待与您交流!-----
今天花一上午学习了张老师关于交通灯管理系统的视频,不得不说老师讲的是在是好,老师也是一般人,也是通过一步步来实现的,coding中也会遇到bug,老师不仅示范了整个项目从创建,到面向对象的思想:“谁有数据,谁就对外提供操作这届数据的方法。”。还有
原始需求:
模拟实现十字路口的交通灯管理系统逻辑,具体需求如下:
异步随机生成按照各个路线行驶的车辆。
例如:
由南向而来去往北向的车辆 ---- 直行车辆
由西向而来去往南向的车辆 ---- 右转车辆
由东向而来去往南向的车辆 ---- 左转车辆
。。
信号灯忽略黄灯,只考虑红灯和绿灯。
应考虑左转车辆控制信号灯,右转车辆不受信号灯控制。
具体信号灯控制逻辑与现实生活中普通交通灯控制逻辑相同,不考虑特殊情况下的控制逻辑。
注:南北向车辆与东西向车辆交替放行,同方向等待车辆应先放行直行车辆而后放行左转车辆。
每辆车通过路口时间为1秒(提示:可通过线程Sleep的方式模拟)。
随机生成车辆时间间隔以及红绿灯交换时间间隔自定,可以设置。
不要求实现GUI,只考虑系统逻辑实现,可通过Log方式展现程序运行结果。
首先对题目进行解读:
通过结合实际,知道在十字路口,每个方向的车可以有三种选择,如由南来的车可以向北,向东,向西走,如此便有12条路线。
再每个方向向右拐的车不受红绿灯影响,如此便只考虑8条路线。再当有车南来北网时,此时也有车北来难往;有车由南向西拐时,此时也有车由北向东拐,如此,只需要考虑4条路线。
现在定为:由南向北(S2N),由南向西(N2W),由东向西(E2W),由东向南(E2S)。
然后视频中从面向对象的角度选择了几个典型的对象:
1,Road(路)
2,Lamp(红绿灯)
3,LampController(灯控制器)
4,MainClass(测试类)
Road拥有创建车和移除车的方法,Lamp代表红绿灯,具有转换颜色的方法,灯控制器能循环控制各个方向上的灯的循环开关
1,Road类
package com.traffic; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; public class Road { private List<String> vechicles=new ArrayList<String>(); private String name; 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 { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } vechicles.add(Road.this.name+"::"+i); } } }); ScheduledExecutorService timer=Executors.newScheduledThreadPool(1); timer.scheduleAtFixedRate(new Runnable(){ @Override public void run() { // TODO Auto-generated method stub if(vechicles.size()>0){ boolean lighted=Lamp.valueOf(Road.this.name).isLighted(); if(lighted){ System.out.println(vechicles.remove(0)+" is passed!"); } } } }, 1, 1, TimeUnit.SECONDS); } }
在这个类中,再一次学习了 java.util.concurrent.Executors工具类,这个类是从1.5才开始有的,具有方法创建同步的单线程,或调度线程。以及内部类中引用外部类的成员变量 Road.this.name.
2,Lamp
Lamp是一个枚举类。因为总共有12条路线,这是确定的,当由南向北的限时用完后再开始走由南向西,接着走由东向西,再由东向南,在循环到开头由南向西。用枚举类可以很好的把路线连接起来,又不会在编程中产生意外的路线。
package com.traffic; public enum Lamp { S2N("N2S","S2W",false),S2W("W2S","E2W",false),E2W("W2E","E2S",false),E2S("S2W","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 next; private String oppo; private boolean lighted; private Lamp(String oppo,String next,boolean lighted){ this.oppo=oppo; this.next=next; this.lighted=lighted; } public boolean isLighted(){ return lighted; } public void light(){ lighted=true; System.out.println(name()+" is green"); Lamp.valueOf(oppo).lighted=true; // if(oppo!=null){ // Lamp.valueOf(oppo).light(); // } } public Lamp blackOut(){ lighted=false; Lamp.valueOf(oppo).lighted=false; System.out.println(name()+" is blackOut and light "+next); Lamp nextLamp=Lamp.valueOf(next); nextLamp.light(); return nextLamp; } }
这里又熟悉了枚举类,枚举类使每个独立的类的对象之间产生了联系。
3,灯控制器
灯控制器的代码很少,主要是调用Executors.newScheduledThreadPool()来定时循环切换红绿灯。
package com.traffic; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; public class LampController { private Lamp currentLamp; public LampController(){ currentLamp=Lamp.S2N; currentLamp.light(); ScheduledExecutorService timer=Executors.newScheduledThreadPool(1); timer.scheduleAtFixedRate(new Runnable(){ public void run(){ currentLamp=currentLamp.blackOut(); } }, 10, 10, TimeUnit.SECONDS); } }
package com.traffic; public class MainClass { public static void main(String[] args) { // TODO Auto-generated method stub String[] directions="S2N,S2W,E2W,E2S,N2S,N2E,W2E,W2N,S2E,E2N,N2W,W2S".split(","); for(int i=0;i<directions.length;i++){ new Road(directions[i]); } new LampController(); } }上面类尤其要注意定义方向时不能写反了,否者出现的错误都不能找到。
通过这个项目,首先学习了如何去面对它,当看到一份需求文档,首先要读通文档,明白关键,把最核心的内容提取出来,像本项目,只需要考虑4条线路就可以,然后保证其他对应的4条线路同步。再就是剩下的4条右拐线路,只需要在定义时加入null,使其和其他线路在构造器中是相同的,再就是使用了java.util.concurrent包。提供了计时器,省去了自己使用实现Runnable接口,自己实现synchronized来创建线程,这些容易出错的代码。
还有就是,把12条线路的”车“装到ArrayList中,这是一个很好的方法,因为可以直接通过操作下标来移除最前面的“车”,然后自动实现后面的车占据前面的位置。
-----Java培训、Android培训、iOS培训、.Net培训、期待与您交流!-----