------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------
十、7K面试题之交通灯管理系统
1. 题目需求
模拟实现十字路口的交通灯管理的系统逻辑,具体需求如下:1,异步随机生成按照各个路线行驶的车辆。
例如:
由南向而来去往北向的车辆---直行车辆
由西向而来去往南向的车辆---右转车辆
由东向而来去往南向的车辆---左转车辆
2,信号灯忽略黄灯,只考虑红灯和绿灯。
3,应考虑左转车辆控制信号灯,右转车辆不受信号灯控制。
4,具体信号灯控制逻辑与现实生活中普通交通灯控制逻辑相同,不考虑特殊情况下的控制逻辑。
注:南北向车辆与东西向车辆交替放行,同方向等待车辆应先放行直行车辆而后放行左转车辆。
5,每辆车通过十字路口的时间为1s(提示:可通过线程sleep的方式模拟)。
6,随机生成车辆时间间隔以及红绿灯交换时间间隔自定,可以设置。
7,不要求实现GUI,只考虑系统逻辑实现,可通过Log方式展现程序运行成果。
2. 图示
3. 设计思路
我们初步设想一下有哪些对象
1,红绿灯
2,红绿灯的控制系统
3,汽车
4,路线
汽车看到自己所在的路线对应的灯绿了就穿过路口么?不是,还需要看其前面是否有车,看前面是否有车,该问那个对象呢?该问路
路中存储着车辆的集合,显然路上就应该有增加车辆和减少车辆的方法了。再看题目,我们这里并不要体现车辆的移动过程,只是捕捉
出车辆穿过路口的过程,也就是捕捉路上减少一辆车的过程,所以,这个车并不需要单独设计成为一个对象,用一个字符串表示就可以了
思路:
创建路对象,路对象里面有车的集合,这个集合会通过线程不断进行变化,而且其中的车元素会通过看其所在路上的灯是否为绿灯而确定是否被移除。
创建灯对象,通过枚举的方法将12个灯描述,并通过构造方法将下一个灯,对面的灯,和灯是否为亮描述一下,然后描述灯的亮与灭的方法,是否为亮的方法。
创建灯的控制器,用于创建两个灯对象之间切换的线程,每隔10秒切换到下一个灯。
创建主函数,在主函数中,创建12个路对象,启动灯的控制器,然后路上的车会根据灯的颜色而选择是否穿行。
面向对象设计把握一个重要的经验:谁拥有数据,谁就对外提供操作这些数据的方法。再牢牢掌握几个典型的案例就可以了:人在黑板上
画圆,列车司机紧急刹车,售货员统计收货小票的金额,你把门关上了等
学员的两个面向对象的面试题,用面向对象的方式设计如下情景。
“两块石头磨成一把石刀,石刀可以砍树,砍成木材,木材做成椅子”
“球从一根绳子的一端移动到了另一端”
class Rope { private Point start; private Point end; public Rope(Point start,Point end){ this.start = start; this.end = end; } public Point nextPoint(Point currentPoint){ /* 通过两点一线的数学公式可以计算出当前点的下一个点,这个细节不属于设计阶段要考虑的问题, 如果当前点是终止点,则返回null,如果当前点不是线上的点,则抛出异常。 */ } } class Ball { private Rope rope; private Point currentPoint; public Ball(Rope rope,startPoint){ this.rope = rope; this.currentPoint = startPoint; } public void move(){ currentPoint = rope.nextPoint(currentPoint); System.out.println("小球移动到了"+currentPoint); } }
4. 创建路对象
package org.huanghai.interview.traffic; import java.util.ArrayList; import java.util.List; 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 List<String> vechicles = new ArrayList<String>(); private String name = null; public Road(String name){ /*构造方法传入路的名称*/ this.name = name; /*用Executors类创建线程池*/ ExecutorService pool = Executors.newSingleThreadExecutor(); /*调用线程方法创建线程*/ pool.execute(new Runnable(){ public void run(){ /*循环产生1000量车,每隔10秒内的随机秒数产生一辆车*/ for(int i=1;i<1000;i++){ try { Thread.sleep((new Random().nextInt(10)+1)*1000); vechicles.add(Road.this.name+"_"+i); } catch (InterruptedException e) { e.printStackTrace(); } } } }); /*创建线程使车辆在路上一辆一辆的移除,看见这条路上的灯变绿了就走*/ ScheduledExecutorService timer = Executors.newScheduledThreadPool(1); timer.scheduleAtFixedRate(new Runnable(){ public void run(){ if(vechicles.size()>0){ boolean lighted = Lamp.valueOf(Road.this.name).isLighted(); if(lighted){ System.out.println(vechicles.remove(0)+" is passing"); } } } },/*运行线程后1秒后开始运行线程代码,然后每隔1秒再运行一次*/ 10, 1, TimeUnit.SECONDS); } }
5. 创建灯对象
package org.huanghai.interview.traffic; public enum Lamp{ /*每个枚举元素各表示灯控制的一个方向*/ S2N("N2S",false,"S2W"),S2W("N2E",false,"E2W"), E2W("W2E",false,"E2S"),E2S("W2N",false,"S2N"), /*由南向东和由东向北不受红绿灯的控制,所以可以假想他们总是绿灯*/ S2E("N2W",true,"S2E"),E2N("W2S",true,"E2N"), /*下面元素表示与上面的元素的相反方向的灯,其中所有的参数值不重要,应忽略不计*/ N2S(null,false,null),N2E(null,false,null), W2E(null,false,null),W2N(null,false,null), N2W(null,true,null),W2S(null,true,null); /*灯是否为绿*/ private boolean lighted; /*与灯同时为绿的对应方向*/ private String next; private String opposite; private Lamp(){} /*枚举的构造函数传入Lamp灯所对应的相反方向的灯,是否是绿灯,下一个方向的灯*/ private Lamp(String opposite,boolean lighted,String next){ this.opposite = opposite; this.lighted = lighted; this.next = next; } /*在Road中通过枚举类的valueOf方法获取与当前路同名的灯的对象,并根据对象的方法isLighted返回灯是否是亮的*/ public boolean isLighted(){ return lighted; } /*把当前对象的灯变绿,并把其相反方向的灯变绿,*/ public void light(){ this.lighted = true; if(opposite != null){ Lamp.valueOf(opposite).light(); } System.out.println(name()+"lamp is green"); } /*当前对象的灯变红,并把其相反方向的灯变红,并把下一个方向的灯变绿*/ public Lamp blackOut(){ this.lighted = false; if(opposite !=null){ Lamp.valueOf(opposite).blackOut(); } Lamp nextLamp = null; if(next !=null){ nextLamp= Lamp.valueOf(next); System.out.println("绿灯从"+name()+"------->切换为"+nextLamp.name()); nextLamp.light(); } return nextLamp; } }
6. 创建灯的控制器
package org.huanghai.interview.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秒再运行一次线程代码*/ 10, 10, /*时间类常量*/ TimeUnit.SECONDS); } }
7. 创建主函数
package org.huanghai.interview.traffic; public class MainClass { public static void main(String[] args) { String[] directions = new String[]{ "S2N","S2W","E2W","E2S","N2S","N2E","W2E","W2N","S2E","E2N","N2W","W2S" }; for(int i=0;i<directions.length;i++){ new Road(directions[i]); } new LampController(); } }