一、需求
1、异步随机生成按照各个路线行驶的车辆。
2、信号灯忽略黄灯,只考虑红灯和绿灯。
3、应考虑左转车辆控制信号灯,右转车辆不受信号灯控制。
4、具体信号灯控制逻辑与现实生活中普通交通灯控制逻辑相同,不考虑特殊情况下的控制逻辑。
5、南北向车辆与东西向车辆交替放行,同方向等待车辆应先放行直行车辆而后放行左转车辆。 每辆车通过路口时间为1秒。随机生成车辆时间间隔以及红绿灯交换时间间隔自定,可以设置。不要求实现GUI,只考虑系统逻辑实现,可通过Log方式展现程序运行结果。
二、总体方案
首先使用名词提炼法,汽车过马路,有汽车,马路,有红绿灯,红绿灯的控制系统四个名词。车通过红绿灯过马路,车之友开启和停下功能。他过马路这个动作不是他控制的,是通过,马路来判断的,马路上有车的集合,某个时刻,马路上少了一辆车,就判断说车过了红绿灯。创建路的对象road,路是代表的某个方向的名字,所以在创建某个方位的路的对象,那条路上就应该有产生车和车过马路的共性行为,所以要创建两个线程来分别操作产生车和定时器来移除车,这里使用到Executors类,能产生单线程和控制器,控制器判断这条路当前的灯是否为绿灯让车通行,并确定通行的实现。
再说红绿灯这个类,我们可以用枚举来实现,因为有12条路,就应该有12个灯,对象是固定值的,由于当前路上的红灯亮时,对面路上的绿灯会亮,所以我们可以创建一个有参的构造函数,参数分别为下一个路口的灯,对面路口的灯和当前灯的明暗情况,启动一个定时器,每隔10秒将当前灯变红将下一个灯变绿。主函数创建路的对象,吧路的名字作为参数循环穿进去,开启控制系统
三、程序代码
1、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实例对象。
* 每条路线上随机增加新的车辆,增加到一个集合中保存。
* 每条路线每隔一秒都会检查控制本路线的灯是否为绿,是则将本路线保存车的集合中的第一辆车移除,即表示车穿过了路口。
* @author Godream
*
*/
public class Road {
//用面向接口的方式,定义一个集合,用来存储和操作车辆这个字符串对象
private List<String> vechicles=new ArrayList<String>();
//定义路线名变量
private String name;
public Road(String name){
this.name=name;
//模拟车辆不断随机上路的过程,使用线程池,通过产生单个线程的方法,创建一个线程池
ExecutorService pool=Executors.newSingleThreadExecutor();
//调用execute方法,可向线程池提交一个任务,让池中的线程执行任务
pool.execute(new Runnable(){
@Override
//复写run方法,需要执行的代码,随机产生车辆,并存入集合
public void run() {
for (int i = 1; i <1000; i++) {
try {
//1到10秒内随机产生一辆车
Thread.sleep((new Random().nextInt(10)+1)*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//车辆进入路线中
vechicles.add(Road.this.name+"_"+i);
}
}
});
//定义一个定时器,每隔一秒检查对应的灯是否为绿,是则放行一辆车
ScheduledExecutorService timer=Executors.newScheduledThreadPool(1);
timer.scheduleAtFixedRate(
new Runnable() {
@Override
//定时器要执行的代码
public void run() {
//判断该路线中是否有车,有则进行放行操作
if (vechicles.size()>0) {
//如果该路线上对应的灯是绿色的,则放行车辆
boolean lighted=Lamp.valueOf(Road.this.name).isLighted();
if(lighted){
System.out.println(vechicles.remove(0)+"\tis traversing!");
}
}
}
},
1,//隔多少秒执行
1,//周期
TimeUnit.SECONDS/*时间单位*/);
}
}
2 、 Lamp 类的编写
package com.isoftstone.interview.traffic;
/**
* 每个Lamp元素代表一个方向上的灯,总共有12个方向,所有总共有12个Lamp元素。
* 有如下一些方向上的灯,每两个形成一组,一组灯同时变绿或变红,所以,
* 程序代码只需要控制每组灯中的一个灯即可:
* s2n,n2s
* s2w,n2e
* e2w,w2e
* e2s,w2n
* s2e,n2w
* e2n,w2s
* 上面最后两行的灯是虚拟的,由于从南向东和从西向北、以及它们的对应方向不受红绿灯的控制,
* 所以,可以假想它们总是绿灯。
* @author Godream
*/
// S2N,S2W,E2W,E2S,N2S,N2E,W2E,W2N,S2E,E2N,N2W,W2S
public enum Lamp {
/*每个枚举元素各表示一个方向上的控制灯*/
S2N(false,"N2S","S2W"),S2W(false,"N2E","E2W"),E2W(false,"W2E","E2S"),E2S(false,"W2N","S2N"),
/*下面元素表示与上面的元素的相反方向的灯,它们的“反方向灯”和“下一个灯”应忽略不计!*/
N2S(false,null,null),N2E(false,null,null),W2E(false,null,null),W2N(false,null,null),
/*下面元素表示四个右转弯方向的灯,因为其不受红绿灯控制,所以可以假设它们总是绿灯*/
S2E(true,null,null),E2N(true,null,null),N2W(true,null,null),W2S(true,null,null);
//当前灯的状态,是否为绿
private boolean lighted;
//当前灯变红时,下个绿的灯
private String next;
//与当前灯相反方向的同为绿的灯
private String opposite;
//构造函数
private Lamp(boolean lighted,String opposite,String next){
this.lighted=lighted;
this.next=next;
this.opposite=opposite;
}
//提供一个判断是否为亮(绿)的方法
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 下面将能看到六个方向的车辆通过。 ");
}
/**
* 某个灯变红时,对应方向的灯也要变红,并且下一个方向的灯要变绿
* @return 下一个要变绿的灯
*/
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;
}
}
3 、 LampController 类的编写
package com.isoftstone.interview.traffic;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* 红绿灯控制系统用来控制红绿灯的切换时间
* 每隔10秒将当前灯变红,并按顺序将下一个方向的灯变绿
* @author Godream
*/
public class LampController {
//定义当前灯用于第一个绿的灯
private Lamp currentLamp;
public LampController(){
//刚开始让由南向北的灯变绿
currentLamp=Lamp.S2N;
currentLamp.light();
//定义一个定时器,每隔10秒就将当前灯由绿变红,并将下一个灯变绿
ScheduledExecutorService timer=Executors.newScheduledThreadPool(1);
timer.scheduleAtFixedRate(
new Runnable() {
@Override
public void run() {
//将下一个灯切换为当前的灯
currentLamp=currentLamp.blackout();
System.out.println("灯变了");
}
},
10,
10,
TimeUnit.SECONDS);
}
}
4 、 MainClass 类的编写
package com.isoftstone.interview.traffic;
/**
* 主程序,用于启动控制系统,并实现题意过程
* @author Godream
*/
public class MainClass {
public static void main(String[] args) {
/*产生12个方向的路线*/
String[] roads={"S2N","S2W","E2W","E2S","N2S","N2E","W2E","W2N","S2E","E2N","N2W","W2S"};
for (int i = 0; i < roads.length; i++) {
new Road(roads[i]);
}
/* 产生整个交通灯系统并运行*/
new LampController();
}
}