您的位置:首页 > 职场人生

黑马程序员_张老师的交通管理灯系统

2014-03-18 14:29 169 查看


---------------------- <ahref="http://edu.csdn.net"target="blank">ASP.Net+Android+IOS开发</a>、<ahref="http://edu.csdn.net"target="blank">.Net培训</a>、期待与您交流! ----------------------

黑马程序员_张老师的交通管理灯系统

这个是本人尝试做得第一个小项目,有些小收获。1.好的英语基础在做项目时,能使程序的阅读性好很多。2程序可以慢慢的调,但是思路一定等清楚,不然绕绕就把自己绕进去了,而且后期调错的时候就累死了。3面向对象必须掌握好

题目:交通灯管理系统

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

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

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

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

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

。。。

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

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

Ø 具体信号灯控制逻辑与现实生活中普通交通灯控制逻辑相同,不考虑特殊情况下的控制逻辑。
注:南北向车辆与东西向车辆交替放行,同方向等待车辆应先放行直行车辆而后放行左转车辆。

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

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

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

关键所在

思路:拿到这道题目后,才发现一个问题,原来基本天天见的红绿灯我真心不是很清楚运作原理。所以我就拿出本子,在上面开始画了。

1 路口有四个方向,先拿一个方向来分析,比如说南(S)

坐南朝北的汽车就有三个方向可以行驶(直行往北(S2N),左拐往西(S2W),右拐往东(S2E))

2 也就是每个方向的车有三种选择,那么四个方向的车加起来就有12中选择。看起来貌似头都糊了。但是细想可以每个方向向右拐的车所面向的灯都假设为恒为绿(这个是张老师的假设,我个人认为只要该方向直行或左拐时灯为绿,那么右拐就一直为绿,),这样已处理,那么就只剩8个了,同时只要考虑相邻两个路口的情况,其他的路口都是一样的。因此只需要考虑四组就行了。例如S2N,S2W,E2W,E2S此处用逆时针顺序)

下面借一下张老师画的图:

3 现在分析下我们要的对象,分别有:路,红绿灯,还有汽车。

4 路:但是仔细一分析汽车在本道题中可以不是对象,他可以是由路提供数据,在判断玩红绿灯后,我们还要判断前面有没有车,有车就要等。所以可以把路看成集合里面存储着不定时,不定量的车,其实可以直接用整数代替。同时路上的方向是死的只有12中,不会改变所以这里可以用上枚举。

5 灯:灯(lamp)主要提供红绿两色,我们可以用开通(light)和闭合(blackout)代替。不但如此我们还要设定lamp变色的时间,和变色后维持的时间。同时这个lamp还要有当自己是blackout时让下一个lamp light的方法。而他的相反方向的灯的显示情况要与 它相反

经分析这道题 大体情况也就这些,经张老师梳理之后发现也并不复杂!下面来看看代码。

先编写Road类

每个Road对象都有一个name成员变量来代表方向,有一个vehicles成员变量来代表方向上的车辆集合。

在Road对象的构造方法中启动一个线程每隔一个随机的时间向vehicles集合中增加一辆车(用一个“路线名_id”形式的字符串进行表示)。

在Road对象的构造方法中启动一个定时器,每隔一秒检查该方向上的灯是否为绿,是则打印车辆集合和将集合中的第一辆车移除掉。

我们在定义包名的时候前面要加上你所面试的那所公司的名称,例如com.isoftstone.interview.traffic
这样可以为自己的应聘增加好感


ExecutorServiceExecutor:执行已提交的 Runnable
任务的对象。

ScheduledExecutorService:一个
ExecutorService
,可安排在给定的延迟后运行或定期执行的命令

public
class
Road {
//定义一个集合用来装载车辆,此处车辆用vechicle不要用car ,用集合方便添加删减
private List<String>
vechicles = new ArrayList<String>();//这里用List比ArrayList好,方便接口
/*每个Road对象都有一个name成员变量来代表方向,有一个vehicles成员变量来代表方向上的车辆集合
*
*/
private String
name = null;
public Road(String name){
this.name = name;

ExecutorService pool=Executors.newSingleThreadExecutor();//Executor:执行已提交的 Runnable
任务的对象。
pool.execute(new Runnable(){
public
void
run(){
for(int i=1;i<1000;i++){
try {
Thread.sleep((new Random().nextInt(10) + 1) * 1000);//random获取随0到9的机数,让线程睡眠不定时间代表下辆车来的等待时间
} catch (InterruptedException e) {
e.printStackTrace();
}
vechicles.add(Road.this.name +
"_" + i);//必须要写上Road.this.name
}
}

});

//每隔一秒检查对应的灯是否为绿,是则放行一辆车

ScheduledExecutorService timer= Executors.newScheduledThreadPool(1);//ScheduledExecutorService:一个 ExecutorService,可安排在给定的延迟后运行或定期执行的命令
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 traversing !");
}
}

}
},
1,//运行时间
1,//间隔时间
TimeUnit.SECONDS);//时间单位

}
}

编写lamp的类:

注意事项:

因为lamp的情况就12种是不变的,所以这里使用枚举更合适:

这个灯除了自身是否开着还必须能控制对面的和下面的灯并且

某个灯变红时,对应方向的灯也要变红,并且下一个方向的灯要变绿
下一个要变绿的灯

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);
这里前两个参数用String类是关键,如果不用String类直接用变量,后面的变量都还没定义就被使用,明显不对。
private Lamp(String opposite,String next,boolean lighted){
this.opposite = opposite;
this.next = next;
this.lighted = lighted;
}

private
boolean
lighted;
/*与当前灯同时为绿的对应方向*/

private String
opposite;
/*当前灯变红时下一个变绿的灯*/

private String
next;
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,下面总共应该有6个方向能看到汽车穿过!");

}

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() +
"-------->切换为" +
next);
nextLamp.light();
}
return nextLamp;
}
}

其实编译到这的时候这个项目的主要难点就都在这了,下面只要写个lamp控制器和主函数就行

LampContorller

整个系统中只能有一套交通灯控制系统,所以,LampController类最好是设计成单例。(这句话很重要,至少我是没想到使用单例,看来还是经验太少了)

LampController对象主要作用就是定义一个定时器,每隔10秒将当前灯变红和将下一个灯变绿

其实这个在lamp里面都定义过一次了

ScheduledExecutorService timer = Executors.newScheduledThreadPool(1);

timer.scheduleAtFixedRate(

newRunnable(){

public void run(){

currentLamp = currentLamp.blackOut();

}

},

10,

10,

TimeUnit.SECONDS);

为了提高代码的阅读性,我们将参数分行写

---------------------- <ahref="http://edu.csdn.net"target="blank">ASP.Net+Android+IOS开发</a>、<ahref="http://edu.csdn.net"target="blank">.Net培训</a>、期待与您交流! ----------------------

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: