交通灯管理系统

项目需求:

 

模拟实现十字路口的交通灯管理系统逻辑,具体需求如下:

 

异步随机生成按照各个路线行驶的车辆。


例如:
由南向而来去往北向的车辆 ---- 直行车辆
由西向而来去往南向的车辆 ---- 右转车辆
由东向而来去往南向的车辆 ---- 左转车辆


信号灯忽略黄灯,只考虑红灯和绿灯。


应考虑左转车辆控制信号灯,右转车辆不受信号灯控制。


具体信号灯控制逻辑与现实生活中普通交通灯控制逻辑相同,不考虑特殊情况下的控制逻辑。


注:南北向车辆与东西向车辆交替放行,同方向等待车辆应先放行直行车辆而后放行左转车辆。


每辆车通过路口时间为1秒(提示:可通过线程Sleep的方式模拟)。

 

随机生成车辆时间间隔以及红绿灯交换时间间隔自定,可以设置。

 

不要求实现GUI,只考虑系统逻辑实现,可通过Log方式展现程序运行结果。

 

 

程序最后结果演示:


现实模拟:

 

  如图所示:一个十字路口分,东,南,西,北四个方向,每个方向又分左行道与右行道,每条行道上又分出,左转道,右转道,直行道。

 

  依据国内的交通法则,行人与车辆应该靠右行驶。在任何时候相对于车辆的前进方向来说都应该在靠右行驶。

 

  排除掉已经通过路口的车辆不算,那么还剩下东,南,西,北四个方向上的右行道车辆,也就是12条道。

 

  因为右转向车并不会与其它车产生行道交错,故而右转向车并不受交通灯的影响,剩下来的就只剩8条道,也就是说需要控制8条道上的车,也就是8个灯。如图中蓝色箭向的方向。

 

  南向北,北向南来往的车并不会行道交错,所以南向北,北向南灯可以保持一致。同理,东西向也是如此。

 

  南向西,北向东行驶的车也不会产生彼此交错影响,所以交通灯也可以保持一致,同理,东向南与西向北也是如此。

 

  经以上分析得出,我们需要控制8个交通灯,而这8个灯中有一半是一致的,换句话说我们只需要4个灯。

 

 

项目分析:

 

  1.12个灯对应12条道路,12条道路对应12个对象,每条道路对象应该知道当前自己所拥有的车辆和自己的灯,根据谁拥有数据谁就提供数据的操作方法这一面向对象设计推理,那么道路对象还应该提供出一个车辆减少方法和增加方法。

 

  2.车辆的减少与增加行为处于两个平行线互不影响,所以需要两个独立的线程来完成这一工作,可以将道路提供的增加车辆与减少车辆方法封装进线程run方法中。车辆的储存使用一个集合列队,该集合需要同步化。因为每一个道路对象都拥有自己的车辆队列集合,增加车辆方法和减少车辆方法,所以每一个道路对象自身都有两个独立的线程在操作同一个集合。

 

  3.增加车辆方法由随机数决定向集合末尾增加新车辆的时间,减少车辆的方法需要调用当前道路对应的灯的状态决定是否减车。

 

  4.使用枚举表示不同道路上的灯,因为需要数据统一化实现多态性的方法调用,所以12条道产生12个灯,4个右转向灯为长亮灯。其余8个灯其中有一半互不影响所以可以将互不影响的两个灯绑定在一起。

 

  5.灯本身应该提供转绿与转红的方法即开关方法,在一个灯开或关的同时应该影响到与它绑定的那个灯,关闭时需要通知下一个灯亮起。在这个过程中可能会涉及到一个死循环或空指针问题,所以必须判断当前灯是不是有被绑定的灯,是不是有下一个灯。

 

  6使用一个独立的线程,从一个起始亮起的灯开始,调用它的关闭方法。它的关闭方法会同时关闭与之绑定的灯,同时通知它的下一个灯亮起。由于12个灯中4个右转灯不用管,剩余8个又有一半反方向灯时间与另一半相同,所以程序只需要控制4个灯的循环亮起即可。

 

 

 

代码实例:

Lamp枚举

public enum Lamp {
	//需要控制的四个灯	
	S2N("N2S", "S2W"), S2W("N2E", "E2W"), E2W("W2E","E2S"), E2S("W2N", "S2N"),
	//与控制的四个灯相反方向的四个灯
	N2S, N2E, W2E, W2N,
	//右转道长亮灯
	S2E(true), E2N(true), N2W(true), W2S(true);
	
	Lamp(String opposite, String next) {
		this.opposite = opposite;
		this.next = next;
	}
	
	Lamp(boolean lighted) {
		this.lighted = lighted;
	}
	
	Lamp(){}
	
	//与当前灯相反方向灯
	private String opposite = null;
	//当前灯变红时下一个变绿的灯
	private String next = null;
	//当前灯状态
	private boolean lighted = false;
	//判断当前灯的状态
	public boolean isLighted() {
		return lighted;
	}
	//打开当前灯与相反方向的灯
	public void light() {
		lighted = true;
		if(opposite != null) {
			Lamp.valueOf(opposite).light();
			System.err.println(this + ","  + Lamp.valueOf(opposite) + ":路灯已转为[绿灯]!");
		}
	}
	//关闭当前灯与相反方向的灯
	public Lamp blackOut() {
		lighted = false;
		if(opposite != null) {
			Lamp.valueOf(opposite).blackOut();
			System.err.println(this + ","  + Lamp.valueOf(opposite) + ":路灯已转为[红灯]!");
		}
		//如果有下一个灯那么通知它开启
		Lamp nextLamp= null;
		if(next != null){
			nextLamp = Lamp.valueOf(next);		
			nextLamp.light();
		}
		return nextLamp;
	}
	//用于打印输出
	@Override
	public String toString() {
		String str = "从" + eToC(name().charAt(0)) + "到" + eToC(name().charAt(2));
		if (this.ordinal() >= S2E.ordinal()) {
			str += "走<<右行道>>不用看路灯很快";
		}else if(this.ordinal() % 2 == 0){
			str += "<<直行道>>";
		}
		else {
			str += "走<<左行道>>请注意安全";
		}
		return str;
	}
	
	//用于转换字符
	private String eToC(char e) {
		String str = null;
		switch (e) {
		case 'E':
			str = "东";
			break;
		case 'S':
			str = "南";
			break;
		case 'W':
			str = "西";
			break;
		case 'N':
			str = "北";
			break;
		}
		return str;
	}
}


 

LampController灯控制器

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class LampController {
	//当前灯
	private Lamp currentLamp = Lamp.S2N;
	public LampController(int durationTime) {
		//将第一个灯设置为红灯
		currentLamp.light();
		//创建一个定时线程池
		ScheduledExecutorService timer = Executors.newScheduledThreadPool(1);
		//每隔durationTime秒触发一次线程
		timer.scheduleAtFixedRate(
				new Runnable() {				
					@Override
					public void run() {
						//调用当前灯的关闭方法,并记录返回的下一个灯
						currentLamp = currentLamp.blackOut();
					}
				}, 
				durationTime, 
				durationTime, 
				TimeUnit.SECONDS);
	}
}


 

Road道路

import java.util.*;
import java.util.concurrent.*;

public class Road {
	//车辆集合
	private List<String> vechicles = Collections.synchronizedList(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() {
				//循环产生车辆
				String str = null;
				for (int i = 1; i < 1000; i++) {
					try {
						//每产生一辆车随机休息1到10秒
						Thread.sleep((new Random().nextInt(10) + 1) * 1000);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					str = Lamp.valueOf(Road.this.name) + "---第" + i + "辆车";
					//将新产生的车辆加入到集合中
					vechicles.add(str);
				}
			}		
		});
		
		//开启新的线程池用于查看当前灯状态放行车辆
		ScheduledExecutorService timer = Executors.newScheduledThreadPool(1);
		//建立线程触发器
		timer.scheduleAtFixedRate(
				new Runnable() {			
					@Override  
					public void run() {
						//判断当前道路上是否有车
						if (vechicles.size() > 0) {
							//调用枚举的静态方法,以枚举的字符串表现形式做为参数获取该枚举对象
							if (Lamp.valueOf(Road.this.name).isLighted()) {
								//如果是绿灯那么通过一辆车
								System.out.println(vechicles.remove(0) + "通过路口!");
							}
						}
					}
				},
				1, //1时间后启动触发器
				1, //每隔1时间触发一次
				TimeUnit.SECONDS);//触发器单位时间量为秒
	}
}


 

Main函数入口

public class MainClass {

	public static void main(String[] args) {	
		//使用数组转载12个灯,便于后续操作。		
		String[] directions = new String[]{
				"S2N","S2W","E2W","E2S",
				"N2S","N2E","W2E","W2N",
				"S2E","E2N","N2W","W2S"};
		//循环创建12个道路对象,并将对应的灯传递进去
		for(int i=0;i<directions.length;i++){
			new Road(directions[i]);
		}	
		//参数用于指定灯转换的时间间隔	
		new LampController(10);
	}
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值