注:颜色相同的为相反方向的路线,粗线条①②③④代表参考线路S2N,S2W,E2W,E2S,细线条代表与参考方向对称的反方向线路N2S,N2E,W2E,W2N,还有四个不受阻碍的四个方向S2E,E2N,N2W,W2S ;
如图所示总共有12条线路,任何情况下都可以向右转,所以这四条 :S2E,E2N,N2W,W2S不用考虑,剩下的8条线路每两条都相互对应,所以只要考虑其中四条,所以挑选其中四条作为参考路线即:S2N①,S2W②,E2W③,E2S④。
车是在路上的,是按照所在路的灯的颜色来判断是否通过,所以只要只需要创建路(Road)和灯(Lamp)这两个对象,此外,灯还要改变颜色,所以再创建一个控制系统对象,这三个对象就可以完成一个模拟的交通灯系统。
先创建路这个类,因为路上有车,所以可以把路看成用来存放车辆的数组,在创建路(Road)这个对象的时候就得有一个数组,并且有不确定数量的车,而且这条路上增加车辆的时间也不确定,解决这个问题可以用线程池中的一个不确定休眠时间线程来操作添加车辆这个动作,这是一个新知识点如下:
ExecutorService pool=Executors.newSingleThreadExecutor();//创建单一线程的线程池
pool.execute(new Runnable(){
public void run(){
//此线程要执行的动作
for(int i=1;i<500;i++)
{
try
{
Thread.sleep(((new Random().nextInt(10))+1)*1000);//随机0-10秒的休眠
}
catch (Exception e) {
}
vehicles.add(Road.this.name+"_"+i);//向数组(路)中增加车辆
}
}
});//end
车辆通过路口就相当于在数组中去掉排在数组第一位的元素,车辆只能在这条路是绿灯的情况下通行并且是时时刻刻都在都在先判断再通行,它是一个周期性重复动作,所以可以用定时器实现代码如下:
ScheduledExecutorService scheduled=Executors.newScheduledThreadPool(1);//只有一个线程的调度线程池
scheduled.scheduleAtFixedRate(new Runnable(){//频率固定的定时器
public void run(){
if(vehicles.size()>0)
{
boolean lighted=Lamp.valueOf(Road.this.name).isLighted();//获取路的灯的状态
if(lighted)
{
System.out.println(vehicles.remove(0)+"穿过马路");
}
}
}
},
1,//延时
1,//周期
TimeUnit.SECONDS);//单位是秒
}
接着创建灯(Lamp)这个类,因为每条路都有自己对应的灯,所以灯也是有12个,既然数量是固定的,跟星期的天数是一个道理,可以用JDK1.5新特性枚举来穿件这个类,
枚举的构造函数必须在列表的下面,灯的每个对象的参数都有与它反方向的灯和下一个方向的灯,还有灯的状态这三个参数,所以得定义三个与之对应的属性,此外,这个类还要有获取当前灯的状态,把当前灯变成绿色和红色三个方法(函数),当前的灯变成绿色/红色,也应该把相反方向的灯也变成红色,代码如下:
//Lamp类
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 nextLamp;
private boolean lighted;
private Lamp(String opposite,String nextLamp,boolean lighted)
{
this.opposite=opposite;
this.nextLamp=nextLamp;
this.lighted=lighted;
}
public boolean isLighted(){//获取当前对象的状态,是红灯还是绿灯
return lighted;
}
public void light()//吧当前的灯变成绿色的
{
this.lighted=true;
if(!(nextLamp.equals("null")))//把与之对称的相反方向也变成绿色
{
Lamp.valueOf(opposite).light();
}
System.out.println(name() + " lamp is green,下面总共应该有6个方向能看到汽车穿过!");
}
public Lamp blockOut()//变红的方法
{
Lamp next=null;
this.lighted=false;
if((!opposite.equals("null")))
{
Lamp.valueOf(opposite).blockOut();//把对应线路变成红灯
}
if(!(nextLamp.equals("null")))
{
next=Lamp.valueOf(nextLamp);//吧下一个方向变成绿灯
System.out.println("绿灯从" + name() + "-------->切换为" + next);
Lamp.valueOf(nextLamp).light();
}
return next;
}//end
第三个类控制器类,在参考线路里取出一条线路赋值给控制器对象的当前的灯,并把它变成绿色,然后创建一个定时器,以一定周期调用Lamp类中的blockOut()方法,该方法的返回值类型是灯,准确的说是当前对象的下一个方向的灯,这样就形成了一个循环①→②→③→④→①,代码如下:
//控制器
public class LampController {
private Lamp currentLamp;
public LampController()
{
currentLamp=Lamp.S2N;//当前灯
currentLamp.light();//
ScheduledExecutorService scheduleds=Executors.newScheduledThreadPool(1);//定时器
scheduleds.scheduleAtFixedRate(new Runnable(){
public void run(){
currentLamp=currentLamp.blockOut();
}},
10,
100,
TimeUnit.SECONDS);
}
}//end
要运行这个程序就得有主函数:
//主函数
public class Main {
public static void main(String[] args) {
String[] roads=new String[]{"S2N","S2W","E2W","E2S","N2S","N2E","W2E","W2N","S2E","E2N","N2W","W2S"};
for(String road :roads)
{
new Road(road);//创建12个路的对象
}
new LampController();//定时器对象
}
}end
|