做好交通灯系统最重要的是理解4条主线,即上面的4种情况,它们是源头,可以引出另外的
情况。
为何只简化为四种情况就可以涵盖所有呢?
现实生活中,为了避免十字路口车流发生交错,只允许车流并行(对开,如图1和3)和分行(各走一边不交叉,如图2和4),这样就保证了车辆能快速,不接触的行驶过路口。
还有一个特殊的情况,就是任何时候车辆只要是右转的,都是随时通行,不用看灯的,因为
右转不会导致车流的交错,所以它默认始终是绿灯,其实现实中,右转有专门的小道(辅路),不受限制。
上图是一个循环往复的过程,第四个图结束后,北面车开始对开,和第一幅图是一模一样的,因为
南边车对开时,北边车也是对开的,立即了四幅图的循环和右转的默认绿灯后,就可以写出一个
枚举类,对灯进行定义了:
1: package com.isoftstone.interview.traffic;
2: public enum Lamp {//要控制的4条主线
3: //四个灯是一个循环,最后一个灯的下一个等是第一个灯
4: //枚举元素灯的构造函数有三个系数:1.传入对应的灯,2.我的下一个灯,3.刚开始我是否是亮的
5: //所谓对应的灯就是相对方向上的灯,他们的变化总是一致的,是一对,控制一个 就可以了
6: //设置下一个灯的原因是这个灯现在是什么状态就决定了它下一个灯的状态。
7: //之所以传入的参数灯都是字符串类型是因为,如果传入灯的枚举元素,
8: //那么由于枚举元素是先定义后使用,就会导致后面才定义的 灯前面无法使用
9: S2N("N2S","S2W",false),
10: S2W("N2E","E2W",false),
11: E2W("W2E","E2S",false),
12: E2S("W2N","S2N",false),
13: //对应的相反线,相反的灯 不能有对应等和下一个灯,否则死循环,我们只控制4条主线上的灯,其他灯都是被控制的对象
14: N2S(null,null,false),N2E(null,null,false),
15: W2E(null,null,false),W2N(null,null,false),
16: //自动右转线,往右转不受灯的控制,始终绿灯ture。
17: S2E(null,null,true),E2N(null,null,true),
18: N2W(null,null,true),W2S(null,null,true);
19: //灯类的成员变量
20: private String next;
21: private boolean lighted;
22: private String opposite;
23: //灯的有参数构造方法
24: private Lamp(String opposite,String next,boolean lighted)
25: {
26: this.opposite=opposite;
27: this.next=next;
28: this.lighted=lighted;
29: }
30: //灯的空参数构造方法
31: private Lamp()
32: {
33: }
34: //灯的一个方法返回一个布尔型变量:亮了
35: public boolean isLighted()
36: {
37: return lighted;
38: }
39: //灯的另一个方法:把自己和对面的灯同时变亮。
40: public void light()
41: {
42: //自己变亮
43: this.lighted=true;
44: //如果是主线的灯,则它有对应的等,让对应的灯也亮
45: if(opposite!=null)
46: {
47: //调用自己,由于对应的灯就没了对应的等了,所有结果就是对应的等亮了,不会产生死循环
48: Lamp.valueOf(opposite).light();
49: }
50: //name枚举出来当前是哪个灯在调用变亮方法,把它打印出来
51: System.out.println(this.name()+"灯变绿了");
52:
53: }
54: //灭灯的方法:除了把当前的和它对应的灯灭掉,还要把下一个灯变绿,同时返回,下一个灯是谁?
55: public Lamp blackOut()
56: {
57: //调用方法则灭灯
58: this.lighted=false;
59: //同时把自己对应的灯也灭掉,因为对应灯的变化始终一致
60: if(opposite!=null)
61: {
62: Lamp.valueOf(opposite).blackOut();
63: }
64: Lamp nextLamp=null;
65: //如果有下一个灯,那么我把他变绿
66: if(next!=null)
67: {
68: nextLamp=Lamp.valueOf(next);
69:
70: System.out.println("绿灯从"+name()+"切换为了"+next);
71: //点亮下一个灯,light()方法被调用后,会自动把下一个灯的对应灯也处理了
72: nextLamp.light();
73: }
74: //灭掉一个灯的同时,返回下一个灯是谁,以便控制下一个灯
75: return nextLamp;
76: }
77: }
有了灯后,还需要一个控制器,对灯的亮(绿灯)和灭(红灯)进行控制,代码如下:
1: package com.isoftstone.interview.traffic;
2:
3: import java.util.concurrent.Executors;
4: import java.util.concurrent.ScheduledExecutorService;
5: import java.util.concurrent.TimeUnit;
6: //定义灯控制器类,用于控制灯变化的频率,并默认红灯就是当前绿被灭。
7: public class LampControllar
8: {
9: private Lamp currentLamp;
10: public LampControllar()
11: {
12: currentLamp=Lamp.S2N;//设定一开始绿的等是路S2N的灯
13: currentLamp.light();//系统开始,第一个等变绿
14:
15: //定义一个计时器,每隔一段时间就让这个灯变红,让下一个变绿
16: //利用线程池技术Executors ,用一个计时器线程来控制灯的变换
17: ScheduledExecutorService timer=Executors.newScheduledThreadPool(1);
18: //scheduleAtFixedRate方法的使用
19: timer.scheduleAtFixedRate(
20: new Runnable()
21: {
22: public void run()
23: {
24: //调用blackOut()方法,每隔十秒钟就把当前的等变黑,该方法返回值是下一个灯,
25: //下一个灯自动成为当前灯,十秒后又被灭掉
26: currentLamp=currentLamp.blackOut();
27: }
28: },
29: 10, //多少秒后执行灭灯方法
30: 10, //多少秒后接着执行灭灯方法
31: TimeUnit.SECONDS);//计量时间的单位是秒
32: }
33:
34: }
灯的功能做好了以后,还需要对路上的车进行控制:
1: package com.isoftstone.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: //路集合所有的资源就是它上面放了很多车,车(vechicles)就是集合的元素
14: List<String> vechicles =new ArrayList<String>();
15: //定义私有化的成员变量neme,它后来指向的是某个方向,即用方向来区分不同的路
16: private String name=null;
17: public Road(String name)
18: {
19: //创建一个产生车的线程,用以模拟路上随机产生车的数量
20: this.name=name;
21: ExecutorService pool=Executors.newSingleThreadExecutor();
22: pool.execute(new Runnable()
23: {
24: public void run()
25: {
26: for(int i=1;i<1000;i++)
27: {
28: try
29: {
30: //每隔1至10秒产生一辆车
31: Thread.sleep((new Random().nextInt(10) + 1)*1000);
32: }
33: catch (Exception e)
34: {
35: // TODO: handle exception
36: }
37: //所谓产生一辆车就是往路集合里添加一个车元素
38: //为当前的路集合(有名字的,指定方向的路)添加一个车
39: vechicles.add(Road.this.name+"路上的第"+i+"台车");//内部类调用外部类属性的格式
40: }
41: }
42: });
43: //定义一个定时器
44: ScheduledExecutorService timer=Executors.newScheduledThreadPool(1);
45: timer.scheduleAtFixedRate(//固定频率的干某事
46: new Runnable()
47: {
48: public void run()
49: {
50: //如果路上有车
51: if(vechicles.size()>0)
52: {
53: //灯是不是亮的问路,获取当前路上的灯是不是亮的
54: boolean lighted=
55: Lamp.valueOf(Road.this.name).isLighted();
56: //如果当前路上的灯是亮的,则打印的同时移除掉开过去的车(始终移除集合里的第一个车)
57: //现实中,第一个车过不去,其他车都过不去
58: if(lighted==true)
59: {
60: //打印看看那个路上的车开过去了
61: System.out.println(vechicles.remove(0)+"is traversing!");
62: }
63: }
64: }
65: },
66: 1, //多少秒以后去干这个事
67: 1, //多少秒以后再接着干
68: TimeUnit.SECONDS);//申明前面数字的度量单位是什么
69:
70: }
71:
72: }
定义一个开启整个程序的类:
1: package com.isoftstone.interview.traffic;
2: //程序开启的类
3: public class MainClass
4: {
5: //把枚举类中的每个灯作为数组元素,赋给一个方向数组
6: public static void main(String[] args)
7: {
8: String [] directions=new String[]
9: {
10: "S2N","S2W","E2W","E2S","N2S","N2E","W2E","W2N","S2E","E2N","N2W","W2S"
11: };
12: //12个方向的路上同时开始产生车
13: for(int i=0;i<directions.length;i++)
14: {
15: new Road(directions[i]);
16: }
17: //灯控制器开始工作
18: new LampControllar();
19: }
20: }