一,异步随机生成按照各个路线行驶的车辆。
例如:
由南向北的车辆----直行车辆
由西向南的车辆----右转车辆
由东向南的车辆---左转车辆
二,信号灯忽略黄灯,只考虑红灯和绿灯。
三,左转的车辆要受交通灯控制,右转车辆不受信号灯控制。四,信号灯的控制逻辑和现实 现实中的交通灯控制逻辑相同,不考虑特殊情况下的控制逻辑。
注:南北向的车辆与东西向的车辆交替放行,同方向等待的车辆应先放行直行车辆,然后再放行左转车辆。
五,每辆车通过路口的时间为1秒。
六,随机生成车辆,及定时改变交通灯状态。
需求分析和设计
首先,分析路口中车辆行驶的方向,用以下的图例来描述各个车辆的行驶方向:
上图是演示的一个十字路口,并有12个行驶方向。
一,东南西北直行方向的同时,汽车还可以向左转;即相对的方向有两个行驶方向;
那么四个方向就有了8条行驶方向。
二,由于汽车始终可以向右行驶,所以又转的交通灯始终为绿。此处就有4条行驶方向。
经过以上分析,抽象出以下几个类:路,交通灯,汽车,交通灯控制器。
对类的设计:
汽车的设计:
一,汽车的主要操作是添加到路中,或者绿灯时移除出路。所以只要用一个随机数来描述汽车就可以了。
路的设计:
一,路上的汽车是有多个的,所以要用集合来接收汽车。
二,路上的汽车是随机出现的,所以要程序在随机的时间增加一辆车。
三,如果路灯为绿时,则在绿灯时间内,将第一辆车移出。
四,因为交通灯是每个一定时间就改变的,所以路也要有一个功能,在每个一定时间久检查交通灯的,车辆是否可行驶。
灯的设计:
注:此处忽略黄灯,因为黄灯是红灯和绿灯之间转换的一个缓冲,所以忽略也不会对系统有影响。
一,因为有12个行驶方向,所以就要有12个对应方法的灯。
二,每一个等都只能有一个,而不是每一次new都是一个新的,所以灯的类型设计为枚举,保证唯一。
三,灯都要有是否是亮的,所以灯要有一个属性来描述状态:(亮(绿灯)或不亮(红灯)),还要有一个亮灯的方法,一个灭灯的方法。
四,由于向右行驶的方向总是可以行驶的,是不受控制的,但为了统一处理方式,就假设出4个右转的灯,
并将这些灯设置为总是可以通行的。
五,其他8个方向中,都是相对出现的,所以只要控制4组灯就可以了,而每一组灯都是相对应的灯,所以只要用4个灯控制就可以了。
当前灯和对应灯亮,时间过之后呢,当前灯灭,下一个灯亮。依次这样执行。
灯的控制器的设计:
一,控制器要控制灯,所以控制器一有一个灯的属性,通过它类控制灯。
二,因为控制器是每个一定的时间才去改变的灯的,所以灯要有一个定时器。
类的编码:
路的代码:
一,增加车辆;
二,定时检查交通灯的情况;
三,绿灯时,移出车辆。
package com.itheima.traficdemo;
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;
/**
* 路
* 实现方式:
* 1,Executors的newSingleThreadExecutor方法,获得ExecutorService 执行权服务对象。来执行这个线程器,
* 随机产生汽车。
* 2,再利用Executors获取定时器对象,并且调用scheduleAtFixedRate来执行定时功能!
* @author wuyong
*
*/
public class Road {
private String name;
private List
vechicals = new ArrayList
();
public Road(String name){
this.name = name;
//以下是模拟现实中,路上出现的车辆。
//JDK1.5的新功能,是java的状态并发库。线程池。类似以数据库连接池。已启动就存在线程。空闲则使用。
//ExecutorService,相当于线程池。必须记住Executors来获得线程池。
ExecutorService pool = Executors.newSingleThreadExecutor();
//启动线程
pool.execute(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 1000; i++){
try {
//用随机值来模拟现实中的随机出现车辆。
Thread.sleep((new Random().nextInt(10) + 1) * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//内部类要调用本类的成员变量,必须要用类名.this.内部类的同名变量!或者是方法的final局部变量或者final参数
//将车辆添加到交通工具集合中。
vechicals.add(Road.this.name + "..." + (i + 1));
}
}
});
//定义一个定时器。
//指定每隔多长时间,检查交通灯的状态,如果交通灯是绿的,则对应方向的车前行。
ScheduledExecutorService timer = Executors.newScheduledThreadPool(1);
timer.scheduleAtFixedRate(
//指定定时器要做的任务
new Runnable() {
@Override
public void run() {
if (vechicals.size() > 0) {
//检查当前灯是否是绿色的。true表示绿色,可以通行。
boolean isLighted = Lamp.valueOf(Road.this.name).isLighted();
if (isLighted) {
//vechicals.remove(0)返回的是被移出的那个元素
System.out.println(vechicals.remove(0) + " 向前行驶。。。");
}
}
}
},
//多长时间开始执行指定的任务
1,
//隔多长时间继续执行指定的任务
1,
//指定的时间间隔的时间单位,用TimeUnit来指定!!
TimeUnit.SECONDS);
}
}
灯的代码:
一,灯的状态;
二,亮灯的方法;
三,灭灯的方法。
package com.itheima.traficdemo;
/**
* 交通灯枚举类
* 实现方式:
* 1,交通灯锁具有的属性,
* 1,交通灯的颜色,
* 2,交通灯的对应的灯,
* 3,交通灯的下一个灯
* 2,交通灯的方法:
* 1,获得交通灯的颜色,
* 2,将交通灯的颜色变为绿色,
* 3,将交通灯的颜色变为红色。
* @author wuyong
*
*/
public enum Lamp {
//因为有12种方向,所以定义了12个灯
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),
W2S(null,null,true),S2E(null,null,true),E2N(null,null,true),N2W(null,null,true);
private Lamp(String opposite,String next,boolean lighted){
this.opposite = opposite;
this.next = next;
this.lighted = lighted;
}
//灯的状态,true为绿,false为红
private boolean lighted;
//当前灯对应的灯。
//注:不能讲Lamp作为对应的灯,因为变量要使用,必须是先声明,再使用。而当前灯的对应灯如果作为构造函数的参数,必须先声明,而当前灯可能还不存在。
private String opposite;
//当前灯的下一个灯
private String next;
//获得当前灯的状态,true为绿色,false为红色。
public boolean isLighted() {
return this.lighted;
}
//将灯,变为绿色
public void linght() {
this.lighted = true;
//如果当前的灯,有对应的灯,则也将对应的灯变成绿色。如果不判断,则会出现死循环,或是报异常。
//枚举可以通过枚举的名字来获得对应的元素。
if (opposite != null) {
System.out.println("现在的绿灯是===========" + name());
Lamp.valueOf(opposite).linght();
}
}
//将当前灯变为红色,将下一个灯变为绿色,并返回
public Lamp black(){
this.lighted = false;
this.lighted = true;
//如果当前的灯,有对应的灯,则也将对应的灯变成红色。
if (opposite != null) {
Lamp.valueOf(opposite).black();
}
//如果当前灯有下一个灯,则将下一个灯变绿色
Lamp nextLamp = null;
if (next != null) {
nextLamp = Lamp.valueOf(next);
nextLamp.linght();
}
return nextLamp;
}
}
交通灯控制器的代码:
一,每隔一定时间,改变交通灯的状态。
package com.itheima.traficdemo;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* 灯的控制器
* 实现方式:
* 1,Executors用执行器,newScheduledThreadPool(1)的线程池获取ScheduledExecutorService对象;
* 2,用获取到的定时器线程对象,调用scheduleAtFixedRate方法,执行定时执行任务
* @author wuyong
*
*/
public class LampControler {
//当前灯
private Lamp currentLamp;
//控制等的状态
public LampControler(){
this.currentLamp = Lamp.S2N;
currentLamp.linght();
//定义计时器
ScheduledExecutorService timer = Executors.newScheduledThreadPool(1);
timer.scheduleAtFixedRate(
//控制器间隔执行的内容
new Runnable() {
@Override
public void run() {
currentLamp = currentLamp.black();
}
},
10,//计时器开始的时间
10, //任务执行的间隔时间
TimeUnit.SECONDS);
}
}
测试类的代码:
package com.itheima.trafficdemo;
/**
* 交通灯测试类
* @author wuyong
*
*/
public class TrafficMainDemo {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
//将12个方向存储到数组中,然后再循环实例化
String[] directions = {
"S2N","S2W","E2W","E2S",
"N2S","N2E","W2E","W2N",
"W2S","S2E","E2N","N2W"};
for (String direction : directions) {
new Road(direction);
}
//实例化交通灯控制器。
new LampControler();
}
}
---------------------- <a href="http://www.itheima.com"target="blank">ASP.Net+Unity开发</a>、<a href="http://www.itheima.com"target="blank">.Net培训</a>、期待与您交流! ----------------------