【黑马程序员】7k面试题之交通灯

时间:2023-02-17 20:16:23

------- Windows Phone 7手机开发.Net培训、期待与您交流! -------

 交通灯项目需求:

模拟实现十字路口的交通灯管理系统逻辑,具体需求如下:

 

        异步随机生成按照各个路线行驶的车辆。

例如:

       由南向而来去往北向的车辆 ---- 直行车辆

       由西向而来去往南向的车辆 ---- 右转车辆

       由东向而来去往南向的车辆 ---- 左转车辆

       。。。

 

       信号灯忽略黄灯,只考虑红灯和绿灯。

 

       应考虑左转车辆控制信号灯,右转车辆不受信号灯控制。

      具体信号灯控制逻辑与现实生活中普通交通灯控制逻辑相同,不考虑特殊情况下的控制逻辑。

注:南北向车辆与东西向车辆交替放行,同方向等待车辆应先放行直行车辆而后放行左转车辆。

 

        每辆车通过路口时间为1秒(提示:可通过线程Sleep的方式模拟)。

 

        随机生成车辆时间间隔以及红绿灯交换时间间隔自定,可以设置。

 

       不要求实现GUI,只考虑系统逻辑实现,可通过Log方式展现程序运行结果。

交通灯项目需求分析思路:

项目为模拟现实生活中的交通信号灯,为方便业务逻辑分析我们先来画图分析。

【黑马程序员】7k面试题之交通灯

项目分为三大主体:路,交通灯,车。

上图所示,根据需求我们得知一共有12条路线。南---->北,北.---->南,南---->西,北---->东,东---->西,西---->东,东---->南,西---->北,南---->东,北---->西,东---->北,西---->南。

每条路有自己的车,车为路的数据,所以根据面向对象设计模式 ,设计Road类,封装road类。 

Road类应该具有的方法和属性。

name:路的方向。

vechicles:存储车辆的集合。

public Road(String name):

构造方法,在创建路对象的时候,因该给路一个名字,然后用这个名字的信号灯来控制此的可行与否。

应该不断有车上路并排队过信号灯,所以创建Road对象时,应该加一个线程,每过若干时间为这条路上增加一辆车。

定时器:路应该每过1秒来判断一下此路是否可通行(是否为绿灯),然后让车队里的每一辆车从第一辆开始过路口。

package com.isoftstone.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(){
//无参构造方法
}
public Road(String name){
this.name=name;//路的方向
ExecutorService pool= Executors.newSingleThreadExecutor();
pool.execute(
new Runnable(){
public void run(){
for(int i=0;i<1000;i++){
try {
Thread.sleep((new Random().nextInt(10)+1)*1000);//随机(1-10)秒后给本路添加一辆汽车
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
vechicles.add(Road.this.name+"_"+i);//随机(1-10)秒后给本路添加一辆汽车



}
}
}

);

ScheduledExecutorService timer= Executors.newScheduledThreadPool(1);
timer.scheduleWithFixedDelay(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 traversing!");
}
}
}

}, 1, 1, TimeUnit.SECONDS);

}
}

上图所示,根据需求我们得知一共有12条路线。南---->北(S2N),北.---->南(N2S),南---->西(S2W),北---->东(N2E),东---->西(E2W),西---->东(W2E),东---->南(E2S),西---->北(W2N),南---->东(S2E),北---->西(N2W),东---->北(E2N),西---->南(W2S)。

12条路线因该由12个信号灯来指挥当前哪条线路可行驶。

信号灯应该具备的属性:

相对的灯:opposite;//相对的灯的可行状态始终和this一样。例:南往北为绿灯,北往南也为绿灯。

接下来变绿的灯;next;

当前灯可行状态:lighted;

方法:

构造方法:Lamp(String opposite,String next ,boolean lighted);//为灯设置属性。

得到灯的可行状态:isLighted();

设置等的可行状态为true:light();

变灯(把当前所有绿灯关闭,开启接下来路线绿灯):blackOut();

需求“:

右转车辆不受信号灯控制

车辆行驶顺序,假如南北先为绿灯:

1. 南---->北   北.---->南

10秒后,南北绿灯变为红灯,南---->北   北.---->南不可行。换为左拐:

2. 南---->西   北.---->

10秒后,南西左拐绿灯变为红灯,南---->西   北.---->东不可行。换为东西直行

3. 东---->西   西---->东

10秒后,东西绿灯变为红灯东---->西   西---->东不可行。换为东西左拐:

4.东---->南   西---->

10秒后。。。第四步跳回第一步,依次循环变灯。



了解需求后,我们来写这个类,因为这12个灯为固定不变,所以这里我用枚举。

package com.isoftstone.interview.traffic;

public enum Lamp {
S2N("N2S","S2W",false),//设置属性
S2W("N2E","E2W",false),
E2W("W2E","E2S",false),
E2S("W2N","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 opposite;//当前绿灯的方向
private String next;//下一个绿灯的方向
private boolean lighted;//
private Lamp(){};
private Lamp(String opposite,String next ,boolean lighted){
this.opposite=opposite;
this.next=next;
this.lighted=lighted;

}
//得到当前灯是否可行。
public boolean isLighted(){
return lighted;

}
//把当前灯和当前灯的对面灯设置为绿灯可行。
public void light(){
this.lighted=true;
if (opposite!=null){
Lamp.valueOf(opposite).light();
}

}
//把当前灯和当前灯对面的灯设置为红灯,并把接下来应该转为绿灯的灯和他的对面灯转为绿灯。
public Lamp blackOut(){
this.lighted=false;
if (opposite!=null){
Lamp.valueOf(opposite).blackOut();
}

//Lamp nextLamp=Lamp.valueOf(next);

Lamp nextLamp = null;
if (next!=null){
//nextLamp=Lamp.valueOf(next);
Lamp.valueOf(next).light();
System.out.println("绿灯从"+name()+"------------>切换为"+next);
}
return nextLamp;
}

}

写到这里灯的设计和代码都写出来,这里还差一个控制灯的一个控制器,让灯每过10秒按照需求变化。

package com.isoftstone.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(){
System.out.println(currentLamp.name());
currentLamp=currentLamp.blackOut();

if(currentLamp==null){
System.out.println("null");
}
}
}


,
10,
10,
TimeUnit.SECONDS
);
}
}
最后一步:创建一个灯控制器和12个方向的路,路会自动增加车辆,灯会每个一段时间自动变换。绿灯的路会让车辆一辆一辆通过。

package com.isoftstone.interview.traffic;

class MainClass {
/**
* @param args
*/
public static void main(String[] args) {
Lamp nextLamp=Lamp.valueOf("dfdfdf");
// TODO Auto-generated method stub
String [] directions=new String[]{
"S2N","S2W","E2W","E2S","N2S","N2E","W2E","W2N","S2E","E2N","E2W","W2S"
};
for(int i = 0 ;i<directions.length;i++){
new Road(directions[i]);
}

new LampController();
}

}

项目感言

交通灯在现实生活中是一个实实在在的项目,虽然我们现在写的这个小程序只是实现了一些个简单的逻辑,但是这个小项目他培养的是编程设计的思维,拿到一个项目首先得会分析需求,然后实现需求。写程序之前学好基础固然重要,但是也一定得会设计程序。一个好的程序员必须要有好的基础和好的思维。这个小项目如果写得出来,我相信我将来可以实现更复杂的逻辑。非常感谢张老师!

------- Windows Phone 7手机开发.Net培训、期待与您交流! -------