交通灯管理系统
----------- android培训、java培训、java学习型技术博客、期待与您交流! ------------
1.模拟实现银交通灯管理系统逻辑
1.1 具体需求如下
(1)异步随机生成按照各个路线行驶的车辆。
例如:
由南向而来去往北向的车辆 ---- 直行车辆
由西向而来去往南向的车辆 ---- 右转车辆
由东向而来去往南向的车辆 ---- 左转车辆
。。。
(2)信号灯忽略黄灯,只考虑红灯和绿灯。
(3)应考虑左转车辆控制信号灯,右转车辆不受信号灯控制。
(4)具体信号灯控制逻辑与现实生活中普通交通灯控制逻辑相同,不考虑特殊情况下的控制逻辑。
注:南北向车辆与东西向车辆交替放行,同方向等待车辆应先放行直行车辆而后放行左转车辆。
(5)每辆车通过路口时间为1秒(提示:可通过线程Sleep的方式模拟)。
(6)随机生成车辆时间间隔以及红绿灯交换时间间隔自定,可以设置。
(7)不要求实现GUI,只考虑系统逻辑实现,可通过Logic方式展现程序运行结果。
具体实现线路图
1.2 概述
方向说明:N(North)---北 ; S(south)-->南方;E(east)--> 东方 ;W(west)-->西方2为英文单词to的意思N2E意思是由北到东。
对应线路:由上图可知一共有12条线路。
而线路可分为直行线路、左转线路、右转线路。
直行线路有S2N,N2S,E2W,W2E;
右转线路有N2W,E2N,W2S,S2E;
左转线路有S2N,N2E,W2E,E2S;
其中由中国的交通情况可知,右转是不需要交通灯讯号的,但为了面向对象编程思想,这里把右转改为有交通灯讯号,且为常绿状态。
而且根据交通知识可知,线程为一对一的关系,即每次放行时,只有一条线路与其相对应的线程通行,其他线路不通行。上图同色线路为对应线路,由上图可知其有4条一一对应线路。(S2N,N2S)、(E2W,W2E)(S2N,N2E) (W2E,E2S)
要求:
这四条一一对应的线程必须遵守线路上的交通灯指示运行与停止。而右转之线路却不用理会。
1.3 简化线路
1)12条线路,每条线路作为一个对象;
2)每条线路由一个红绿灯控制其通、停状态;
3)右转之红绿灯设为常绿;
4)余下的8条线路(两两对应)分为四组
总结:程序只需考虑图中的4条(同色)路线的红绿灯的如何切换即可。
1.4 根据题目要求进行线路切换次序确定
1)将线路分为南北、东西两部分,同方向等待车辆先放直行再放左转车辆。
因为线路为两两对应关系,其实只需要考虑两个方向的线程即可,即S(南)与E(东).
2) 从S方向出发的车有S2W和S2N这两个方向的线路--->要求是先放直行后放左转,所以S2N先施行;S2W后放行。
3)从E方向出发的车有E2W和E2S这两个方向的线路---要求先放行直行再放行左转,所以E2W先放行,E2S后放行。
总结:因为交通灯是循环切换的,所以从那个方向开始是没有关系的,这里就由S开始循环切换。
可得
{2}3. 从S方向或者E方向那个开始都可以,因为这些线路的交通灯是循环切换的。因此这里面从S方向开始。While(true){
S2N(N2S)【1】---> S2W(N2E)【2】---> E2W(W2E)【3】 ---> E2S(W2N)【4】--->S2N(N2S)【1】 --->}
由切换关系可知,由这个交通灯程序只需要考虑两条直线与两条左转线即可(4条线路,忽略同时进行的线路)。
1.5 面向对象的分析
1.5.1 类的提取
交通灯系统中需要用到路线、交通灯与车辆,而交通灯的亮灭不可能是自己决定,所以需要有一个类来控制其的亮灭,所以得有一个交通灯控制器类,所以可以将其分为这三个类 ----- 交通灯类、线路类、车辆类与交通灯控制器类。
1.5.2 模拟过程—车辆穿过一条线路的过程
首先应该先有一辆车,才能在线路上启动运行,所以车辆类的实例应在线路类的实例中产生。一辆车产生后就在线路实例中运行。而且当这条线路上的交通灯为红时,不得通行,这辆车前面有车辆也不得通行。。
1.5.3 类的分析
1.线路类的分析
成员分析:由上思想可得,车辆类一定要在线路的实例中生成,而线路中必然包括一个交通灯类的实例,这个实例是与线路一一对应的。所以可得每条线路的实例都包括相应的车辆与交通灯类的实例。
关系分析:由现实可知,一条交通线路上可以让无数的车辆通过,而每条线路上只有一个交通灯在作用,当然这只是指这个实例上的十字路口。所以可得交通灯类与线路类是一一对应关系,而车辆类与线路类则是N对1的关系。
方法分析:
在本实例中,汽车只是存在于通过线路时,即在通过线路时产生出现,而通过线路后则会自动销毁。所以线路类中有车辆的减少与增加方法。汽车看到前面绿灯了,就可以通行了吗,当然不是,在现实中,就算前面绿灯了,也需要看看自己前面有没有车辆才可通过,当前面没有车辆,且是绿灯时,方可通过,怎么判断车辆位置是不是第一位呢,很明显是用集合的下标表示为佳,所以线路类对象中汽车是以集合形式存储的。
2.交通灯类分析
成员分析:
交通灯如现实上有三种颜色,但实际只是两种颜色起作用,红或绿,因为两种颜色是相互切换的,即---红灯亮时,绿灯灭;红灯灭时,绿灯亮。所以只需要一种灯的状态即可,用绿灯的亮灭表示其线路的通闭状态。
方法分析:
如果线路问题,每个交通灯指挥着相应的线路的通闭,而每个交通灯都应该有其切换交通灯切换通闭的方法,即决定下一个通行的线路的切换。其顺序就是对图分析时的,先真行后左拐,再到另一方向上的直行,左拐。
具体分析:
有12条线路则有12个交通灯,但右拐之灯为常绿状态,其他八条线路为一一对应状态,则只需要4组灯的讯号即可。只需要在4组中各取出一个灯,对这4个灯进行依次轮流变亮,而其对应的灯也相应地一同变亮,灯的轮流变亮,则意味着,每一个交通灯需要知道自己的后一个交通灯,这样才能达到轮流的效果,所以交通灯类中应该有一个变量来记录自己的下一个交通灯。
3.车辆类分析
车辆类在这里只是一个体现车辆穿过线路的过程,也是并不需要车辆类中有相应的方法,所以车辆辆不需要单独设计成一个对象,用一个字符串表示即可。----使用Java内建String类对象来替代自定义的车辆类。
4.交通灯控制器类分析
功能分析:需求:红绿灯切换时间间隔可以是任意的,所以交通灯控制器类中的方法就应该有相应的时间属性并且有设置该时间的方法。而且有切换交通灯的功能的方法。
2.程序编写
2.1 交通灯类Lamp的程序编写
1.由上例的分析可知Lamp类的功能应采用枚举;
分析:12个交通灯对应着枚举中的12个成员对象,Lamp类中的表示对应线路的属性和下一条线路的属性是一一对应关系的,这种一一对应关系可以采用String类型来替代Lamp类聚合的表示对应的Lamp类的实例和表示下一条交通灯的Lamp实例。
2. Lamp类代码示例
1).Lamp的亮灭方法
增加让Lamp变亮和变黑的方法:light和blackOut,对于S2N、S2W、E2W、E2N这四个方向上的Lamp对象,这两个方法内部要让相反方向的灯随之变亮和变黑,blackOut方法还要让下一个灯变亮。
2). Lamp类示例代码
注:编写程序时的包名:因这是面试题,而对方公司为软通公司,所以我们把包名改为com.isoftstone.interview.traffic(面试小技巧);
package com.isoftstone.interview.traffic;
/**
* 每个Lamp元素代表一个方向上的灯,总共有12个方向,所有总共有12个Lamp枚举元素。
* 程序代码只需要控制每组灯中的一个灯即可:----括号中的表示该线路的交通灯对应的线路的交通灯
* S2N(N2S)、S2W(N2E)、 E2W(W2E)、 E2S(W2N) -----受红绿灯控制的交通灯
* S2E(N2W) 和E2N(W2S) -----不受红绿灯控制的交通灯
* */
public enum Lamp {
//每个枚举元素各表示一个线路方向上的控制灯
//左转的两条主路+ 两条直行线 ----初始化这些主路的灯光是灭的---Red
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),
//四条右拐的路常绿 ---四个右转弯方向的灯,因为其不受红绿灯控制,所以可以假设它们总是绿灯
N2W(null, null, true), W2S(null, null, true), S2E(null, null, true), E2N(null, null, true);
//当前灯的状态,是否为绿
private boolean lighted =false;
//当前线路交通灯的对应线路的交通灯
//一对一所以使用String的name替代
private String opposite =null;
//当前线路交通灯的被切换到下一个交通灯
private String next =null;
//一对一所以使用String的name替代
/**
* 构造函数
* @param opposite ----当前线路对应线路的交通灯的名字
* @param next --------当前线路的下一条线路的交通灯的名字
* @param lighted -----这条线路的交通灯初始化的时候被点亮(代表绿灯)
*/
private Lamp(String opposite, String next, boolean lighted){
this.lighted =lighted;
this.opposite =opposite;
this.next =next;
}
/**
* lighted属性的Getter
* @return---获取当前线路的交通灯的状态
*/
public boolean isLighted() {
return lighted;
}
/**
* 点亮该灯----点亮表示将灯变成绿色的
* 某个灯变绿时,它对应方向的灯也要变绿
*/
public void light(){
this.lighted =true;
//同时要点亮对应路段的交通灯
if(this.opposite !=null){
Lamp oppositeLamp =Lamp.valueOf(opposite);
oppositeLamp.light();
}
System.out.println(name()+" lamp is green, 下面可以看到6个方向看到汽车穿过!");
}
/**
* 灭掉该灯----也就是将该路段的交通灯变红
* @return----返回下一站切换的路灯
*/
public Lamp blackOut(){
//当前灯变红,对应方向的灯也变红
this.lighted =false;
//同时要灭掉对应路段的灯
if(this.opposite !=null){
Lamp oppositeLamp =Lamp.valueOf(opposite);
oppositeLamp.blackOut();
}
//点亮下一对应的灯
Lamp nextLamp =null;
if(next !=null){
nextLamp=Lamp.valueOf(next);
nextLamp.light();
System.out.println("绿灯从"+ name()+"--->切换为"+next);
}
return nextLamp;
}
}
2.2 线路类Road程序编写
1. 相应方法
1). 删除方法 ------代表车辆穿过这条线路
每条路线每隔一秒都会检查控制本路线的灯是否为绿,是则将本路线保存车的集合中的第一辆车移除,即表示车穿过了路口。
2). 增加车辆和删除车辆的方法
在上面的分析可知车辆的增删不过是集合的增删而已,所以这两个方法不需要其实方法调用,可以直接放到Road类的构造方法即可。
3). Road类示例代码
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;
/**
* 每个Road对象代表一条路线,总共有12条路线,即系统中总共要产生12个Road实例对象。
* 每条路线上随机增加新的车辆,增加到一个集合中保存。
* 每条路线每隔一秒都会检查控制本路线的灯是否为绿,是则将本路线保存车的集合中的第一辆车移除,即表示车穿过了路口。
*/
public class Road {
//模拟该条路上的汽车集合
private List<String> vehichles =new ArrayList<String>(); //使用List接口 ---面相接口编程
//线路的线路名称 ----- 实际聚合的是Lamp类实例
private String name; //实际通过这个name获取这条线路一对一的Lamp类对象
/**
* Road类的构造方法
* @param name ----该条线路的线路名称
*/
public Road(String name){
this.name =name;
//启动另一个线程来创建该条路上的车辆 ---模拟车辆不断随机上路的过程,使用线程池,通过产生单个线程的方法,创建一个线程池
ExecutorService pool =Executors.newSingleThreadExecutor();
pool.execute(new Runnable(){
//通过for循环来模拟车辆的增加 ----随机时间间隔生成一辆车 间隔不固定
@Override
public void run() {
for(int i=0; i< 1000; i++){
try {
//按照一个随机的时间间隔生成车辆
int randomTime =(new Random().nextInt(10)+ 1)*1000;
Thread.sleep(randomTime);
Road.this.vehichles.add(Road.this.name+"_"+ i);
}catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
});
//启动另一个线程来减少当前这条路上的车以模拟这辆车通过了这条路
ScheduledExecutorService timer =Executors.newScheduledThreadPool(1);
timer.scheduleAtFixedRate(
new Runnable(){
@Override
public void run() {
// TODO Auto-generated method stub
if(vehichles.size() >0){
//查看当前路段对应的交通灯是不是已经亮了亮了的话让该条路上的车辆通过
boolean lighted = Lamp.valueOf(Road.this.name).isLighted();
if(lighted){
System.out.println(vehichles.remove(0)+" is traversing!");
}
}
}
},
1,
1,
TimeUnit.SECONDS);
}
}
2.3 LampController程序编写
1. 切换线路的方法
要求:每隔10s切换一下交通灯。
这个方法仅仅被使用一次之后即可,不需要被其他的方法调用。因此简化程序,就直接放入到LampController类的构造方法即可。
2.LampController 类的设计规范
因为在整个交通灯系统中,交通灯控制器只能有一个,所以LampController类设计为单例模式。
3.LampController类的示例代码
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
*
* LampController类用来切换不同线路的交通灯每隔10秒将当前灯变红,并按顺序将下一个方向的灯变绿
*
*/
public class LampController {
private Lamp currentLamp;
/**
* 初始化第一盏要变绿的红绿灯之后启动新的线程进行线程切换
* LampController设计成单例模式 StepI: 私有化构造方法
*/
private LampController() {
// 指定第一盏亮的交通灯
currentLamp = Lamp.S2N;
currentLamp.light();
// 设置定时器
ScheduledExecutorService timer = Executors.newScheduledThreadPool(1);
timer.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
// 每隔10s切换下一盏亮的交通灯
currentLamp = currentLamp.blackOut();
}
}, 10, 10, TimeUnit.SECONDS);
}
// 单例模式 ---- StepII:饿汉式构建全局访问点
public static final LampController lampController = new LampController();
}
2.4 测试类MainClass程序编写
MainClass类的示例代码
public class MainClass {
public static void main(String[] args) {
//实例化交通灯控制器实例
//在实例化LampController的过程中,会对相应道路的交通灯进行无限循环的切换
//-----启动了新的线程进行切换
LampController lampController =LampController.lampController;
//给出所有的方向
String[]directions =new String[]{
"S2N", "S2W", "E2W", "E2S",
"N2S", "N2E", "W2E", "W2N",
"N2W", "W2S", "S2E", "E2N"
};
//实例化Road的过程
//---- 每一条路的new的过程中会查看这条路的交通灯的颜色并穿过马路 ---- 一个新的线程
//---- 每一条路的自动增加车辆 ---- 有一个新的线程
for(int i=0; i< directions.length; i++){
new Road(directions[i]);
}
}
}
----------- android培训、java培训、java学习型技术博客、期待与您交流! ------------