小项目_交通信号灯


1、背景讨论

十字路口红绿信号灯,怎么控制车辆有序的通过呢?如果每一个入口都可以向其他三个方向行驶,那么就一共有3*4=12种路线,但是不可能12条路线同时通车的,不然就要出事儿了。这12条路线中,哪些路线能同时行车呢?在不出故障的前提下,为了能提高通车效率,就要找出同时最多能有哪些路线通车。

       见下图:


②如上图,有交点的路线就不能同时通车。对应右转弯的那4条路线,我发现,它们与其他路线都没有交点,也就是说它们能随时通车,我把他归结为A类。还有8条路线,

 由于只有"中心对称形式"的线路才不会有交集,于是分出来了下面的五组

   AS2EE2NN2WW2S

   BS2NN2S

   CS2WN2E

   DE2WW2E

   EE2S W2N

③对应同一组的,由于可以同时通车,就是说它们的信号灯应该保持一致。对于不同组的,它们每次只能通行一组。A组由于随时能通车,可以把它们的灯时刻亮着。

 对于BCDE组,每次只能亮一组,为了方便,按照BCDE的顺序依次循环通行吧,这样也比较的公平。 最后,问题就变成了BCCE组 信号灯的切换问题了。  

2、设计实现:

    这个问题涉及到的实体有:信号灯、路、信号灯控制权、车辆,接下来就是为这几个实体设计类了。

 1)对于信号灯:

 ①属性有(对应字段):名称、灯的状态、与它同为一组的信号灯、排在后面亮的信号灯、

②行为(对应方法):获取其名称、获取灯的状态、亮灯、灭灯

③大体代码思路:


public class Lamp {
//1:字段
private String name;
private boolean lighted; //假设true表示绿色,通行
private Lamp  opposite;
private Lamp next;
//2:方法
public Lamp (){
}
public Lamp(String name,boolean lighted,Lamp opposite,Lamp next){
this.name=name;
this.lighted=lighted;
this.opposite=opposite;
this.next=next;
}
public String getName(){
return this.name;
}
public boolean isLighted(){
return this.lighted;
}
public void lighted(boolean b){
this.lighted=b;
}
}


2)对于路

①属性(字段):名称(和信号灯对应)、是否能通车(通过其对应的信号灯来处理)、正在等待的车辆序列

②行为(方法):让车辆排队等着,让符合条件的过去,由于这两个方法需要异步执行的,也就是说等的车子和过去的车子并没有什么顺序可言。所以,需要使用两个线程来处理这两个方法。

③大体代码

import java.util.ArrayList;
import java.util.List;
/**
 * @author Administrator @zsw 2012-7-21 下午07:06:27
 */
public class Road {
//1、字段
private String name;
private List<String> list=new ArrayList<String>();
private boolean canrun;
//2、方法:
public Road(){
}
public Road(String name,List<String> list,boolean canrun){
this.name=name;
this.list=list;
this.canrun=canrun;
}
public void addCar(String car){
list.add(car);
}
public void go(String car){
list.remove(car);
}
Thread addThread=new Thread(new Runnable(){
@Override
public void run() {
while(true){
String car="car";
addCar(car);
}
}});
Thread runThread=new Thread(new Runnable(){
@Override
public void run() {
while(canrun){
go(list.get(0));
}
}});
}


3)再者就是信号灯控制器, 信号灯控制器应该每过固定时间,切换信号灯的颜色.

   

 ①字段:当前通车的信号灯

 ②方法:经过固定时候后,关闭当前的信号灯,打开其下一个信号灯

③大体代码

/**
 * @author Administrator @zsw 2012-7-21 下午07:30:30
 */
public class LampController {
private Lamp currentLamp;
public LampController(){
//在这个地方出问题了,信号灯应该提前准备好,拿来直接用,这时候想到了Enum
//this.currentLamp=new Lamp("S);
}
}


3)对应车子,只是一个过客,来也冲冲,去也冲冲,就用它添加到等待队列中的序号来命名它们吧。

2、上面设计实现出现的问题和改进

 1)信号灯由于有相互的顺序关系,所以需要提前实例化好,在给他们添加顺序,所以选择使用枚举来实例化它们。

代码:


public enum Lamp {
/*每一个枚举元素各表示灯控制的一个方向
 * 它有三个元素:①与之对应的灯 ②下一栈灯 ③状态
 */
//①B1,C1,D1,E1,间隔固定时间,依次亮起
S2N("N2S","S2W",false),S2W("N2E","E2W",false),
E2W("W2E","E2N",false),E2S("W2N","S2N",false),
//②B2,C2,D3,E2
N2S(null,null,false),N2E(null,null,false),
W2E(null,null,false),W2N(null,null,false),
//③四个右转弯的灯,常亮,A1,A2,A3,A4
S2E(null,null,true),E2N(null,null,true),
N2W(null,null,true),W3S(null,null,true);
   
private Lamp(String opposite,String next,boolean lighted){
this.opposite=opposite;
this.next=next;
this.lighted=lighted;
}
private Lamp(){
}
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()+" ----->切换到 "+nextLamp.name());
nextLamp.light();
}
return nextLamp;
}
}


2)路,通过线程池和定时器来完成:线程池用来添加车子,而定时器则是放行车子。

  

package com.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;
/**
 * @author Administrator @zsw 2012-7-21 下午12:12:56
 */
public class Road {
private List<String> vechicles =new ArrayList<String>();
private String name=null;
public Road(String name){
this.name=name;
ExecutorService pool=Executors.newSingleThreadExecutor();
pool.execute(new Runnable(){
@Override
public void run() {
for(int i=1;i<10;i++){
try {
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){
String str=vechicles.remove(0);
System.out.println(str+" is traversing !");
}
}
}},
1,
1,
TimeUnit.SECONDS);
}
}



3)控制器,就很简单了,用一个定时器就完全可以搞定了,设置每过10秒,切换一次信号灯,让不同的路线公平的运行。

 

 package com.traffic;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
 * @author Administrator @zsw 2012-7-21 下午01:40:10
 */
public class LampController {
private Lamp currentLamp;
public LampController(){
currentLamp=Lamp.S2N;
currentLamp.light();
ScheduledExecutorService timer=
Executors.newScheduledThreadPool(1);
timer.scheduleAtFixedRate(
new Runnable(){
@Override
public void run() {
currentLamp=currentLamp.blackOut();
}},
10, 
10, 
TimeUnit.SECONDS);
}
}
4)最后是主程序了,即这个系统的入口,通过一个循环来创建12条路,让每条路都开始工作了,并调用控制权。
package com.traffic;
/**
 * @author Administrator @zsw 2012-7-21 下午01:53:04
 * S2N","S2W","E2W","W2S","  N2S","N2E","W2E","W2N","  S2E","E2N","N2W","W2S
 */
public class MainClass {
public static void main(String[] args) {
String []directions=new String[]{
"S2N","S2W","E2W","W2S",
" N2S","N2E","W2E","W2N",
"S2E","E2N","N2W","W2S"
};
for(int i=0;i<directions.length;i++){
new Road(directions[i]);
}
new LampController();
}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值