【学习并改进】黑马程序员-张孝祥-交通灯管理系统业务

import java.util.*; //导入工具包
import java.util.concurrent.*; //导入工具子包并发包

/**
 * 产生多个方向的路线和整个交通灯系统
 * @author 张孝祥-黑马程序员
 * @editor 魏安-黑马程序员
 */
public class Traffic //交通灯类
{
	public static void main(String[] Ann) //主函数
	{
		String[] directions = {"S2N","S2W","E2W","E2S","N2S","N2E","W2E","W2N","S2E","E2N","N2W","W2S"}; //定义字符串数组为方向路线
		int index = directions.length - 1; //定义数组角标
		Lamp lamp = Lamp.valueOf(directions[index]); //定义枚举值为数组对应角标值
		boolean flag = ( lamp == Lamp.S2E || lamp == Lamp.N2W || lamp == Lamp.E2N || lamp == Lamp.W2S ); //定义判断标记为虚拟绿灯状态
		if ( ! flag ) //如果不符合标记条件
		{
			for ( int i = 0; i < directions.length; i++ ) //对整个数组遍历
			{
				new Road( directions[i] ); //建立道路类对象并传入数组对应角标参数值
			}
			new LampController(lamp); //建立灯控制器对象
		}
		else //否则执行
		{
			System.out.println("目前全部为绿灯状态,无需灯控制器,观察道路车流!"); //打印信息
			for ( int i = 0; i < directions.length; i++ ) //对整个数组遍历
			{
				new Road( directions[i] ); //建立道路类对象并传入数组对应角标参数值
			}
		}
	}
}

/**
 * E = East = 东 W = West = 西
 * N = North = 北 S = South = 南
 * 东西和南北为直线通行类 WE & SN
 * 东南和西北为转折通行类 SE & WN
 * 每个Lamp枚举元素代表一个方向上的灯,总共有12个方向,共有12个Lamp元素。
 * 有如下一些方向上的灯,每两个形成一组,一组灯同时变绿或变红。
 * 所以程序代码只需要控制每组灯中的一个灯即可:
 * s2n,n2s =
 * s2w,n2e ^
 * e2w,w2e =
 * e2s,w2n ^
 * -------
 * s2e,n2w x
 * e2n,w2s x
 * 上面最后两行的灯是虚拟的,由于从南向东和从西向北、以及它们的对应方向不受红绿灯的控制,
 * 所以可以假想它们总是绿灯。
 * @author 张孝祥-黑马程序员
 * @editor 魏安-黑马程序员
 */
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 boolean lighted; //定义判断变量为绿灯通行开关
	private String opposite; //定义字符串变量为与当前灯相同状态对应灯
	private String next; //定义字符串变量为当前灯状态改变时下个会变绿灯
	private Lamp(String opposite,String next,boolean lighted) //枚举构造函数
	{
		this.opposite = opposite; //锁定传入参数变量
		this.next = next; //锁定传入参数变量
		this.lighted = lighted; //锁定传入参数变量
	}
	public boolean isLighted() //判断开关功能
	{
		return lighted; //返回开关值
	}
	/*当某个灯变绿时,它对应方向的灯也要变绿。*/
	public void light() //亮灯功能
	{
		this.lighted = true; //改变开关值
		if ( opposite != null ) //如果对应灯值不为空
		{
			Lamp.valueOf(opposite).light(); //对应灯枚举常量递归执行亮灯功能
		}
		System.out.println("现在 " + this.name() + " 为绿灯,下面共有6个方向能看到汽车穿过!"); //打印此枚举常量名称信息
	}
	/*当某个灯变红时,对应方向的灯也要变红,并且下一个方向的灯要变绿。*/
	public Lamp blackOut() //灭灯功能
	{
		this.lighted = false; //改变开关值
		Lamp nextLamp = null; //定义枚举变量为下个方向灯
		if ( opposite != null ) //如果对应灯值不为空
		{
			Lamp.valueOf(opposite).blackOut(); //对应灯枚举常量递归执行灭灯功能
		}
		if ( next != null ) //如果当前灯状态改变时下个会变绿灯值不为空
		{
			nextLamp = Lamp.valueOf(next); //下个方向灯值为当前灯状态改变时下个会变绿灯枚举常量
			System.out.println("绿灯从" + this.name() + "切换为" + next); //打印此枚举常量名称信息
			nextLamp.light(); //下个方向灯执行亮灯功能
		}
		return nextLamp; //返回下个方向灯枚举值
	}
}

/**
 * 对灯进行控制的方法
 * @author 张孝祥-黑马程序员
 * @editor 魏安-黑马程序员
 */
class LampController //灯控制器类
{
	private Lamp currentLamp; //定义枚举变量为当前灯
	private Runnable TurnLamp = new Runnable() //建立可运行多线程类对象为转换灯操作
	{
		@Override //覆写系统功能标记
		public void run() //覆写系统运行功能
		{
			System.out.println("绿灯切换,可以通行了!"); //打印信息
			currentLamp = currentLamp.blackOut(); //当前灯值为当前灯执行灭灯功能
		}
	}; //匿名内部类调用方式
	public LampController(Lamp lamp) //类构造函数
	{
		currentLamp = lamp; //当前灯为枚举调用值
		currentLamp.light(); //当前灯执行亮灯功能
		/*等10秒后执行且每隔10秒将当前绿灯变为红灯,并让下一个方向的灯变绿*/
		ScheduledExecutorService SES = Executors.newScheduledThreadPool(1); //定义规划执行服务为执行器创建线程池
		SES.scheduleAtFixedRate(TurnLamp,10,10,TimeUnit.SECONDS); //规划执行服务按照参数执行转换灯操作
	}
}

/**
 * 每个Road对象代表一条路线,总共有12条路线,即系统中总共要产生12个Road实例对象。
 * 每条路线上随机增加新的车辆,增加到一个集合中保存。
 * 每条路线每隔一秒都会检查控制本路线的灯是否为绿,是则将本路线保存车的集合中的第一辆车移除,即表示车穿过了路口。
 * @author 张孝祥-黑马程序员
 * @editor 魏安-黑马程序员
 */
class Road //道路类
{
	private int Sleeptime = (new Random().nextInt(10) + 1) * 1000; //定义休眠时间
	private ArrayList Vechicles = new ArrayList(); //建立数组列表为车辆队伍容器
	private String name = null; //定义字符串变量为名字
	private Runnable VechiclesRun = new Runnable() //建立可运行多线程类对象为车辆运行操作
	{
		@Override //覆写系统功能标记
		public void run() //覆写系统运行功能
		{
			for ( int i = 1; i < 1000; i++ ) //定义循环条件
			{
				try //尝试执行
				{
					Thread.sleep(Sleeptime); //线程休眠
				}
				catch ( InterruptedException IE ) //抓住中断异常
				{
					IE.printStackTrace(); //打印堆栈信息
				}
				Vechicles.add(Road.this.name + "_" + i); //往容器添加元素
			}
		}
	}; //匿名内部类调用方式
	private Runnable Released = 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) + " 有车经过!"); //打印容器移除对应角标值信息
				}
			}
		}
	}; //匿名内部类调用方式
	public Road(String name) //类构造函数
	{
		this.name = name; //锁定传入参数变量
		/*车辆不断随机上路过程*/
		ExecutorService ES = Executors.newSingleThreadExecutor(); //定义执行服务为执行器创建单线程
		ES.execute(VechiclesRun); //执行服务执行车辆运行操作
		/*每隔一秒检查对应的灯是否为绿,若是,则放行一辆车*/
		ScheduledExecutorService SES = Executors.newScheduledThreadPool(1); //定义规划执行服务为执行器创建线程池
		SES.scheduleAtFixedRate(Released,1,1,TimeUnit.SECONDS); //规划执行服务按照参数执行放行操作
	}
}


学习心得:在巨人的肩膀上,你会做得更好!


其实个人认为,该程序由于要顾及车辆运行的模拟,而不仅仅是交通灯的工作,所以结构就有点复杂了。

毕竟程序的分解是越小块就越具体,用小细节组成大环境会比较好,而如果要一下子考虑全盘因素,肯定有困难。

当然三天时间做出这样的东西,真的很佩服张孝祥老师!


如果只考虑交通灯的工作运行情况,个人思路如下:

1.红灯亮一段时间,绿灯在这段时间内关闭。

2.红灯灭,绿灯打开一段时间。

3.轮流切换,可以用循环,也可以独立设置时间参数。

4.黄灯的工作要看时机而定。

运行参数的关键在于:开关状态和时间长短


以上只是一组灯的运行方式,如果考虑多组灯,请使用多线程或者多步操作完成。无非是逻辑执行而已。

由于本人并非做过这种项目,只能管中窥豹了,如有指教,请在本文评论,谢谢!


原帖:http://blog.csdn.net/zhangxiaoxiang/article/details/6273384

张孝祥老师已逝,可惜!无论世人如何评价他,起码他都是个实实在在做事的人!就凭这一点,就值得世人敬佩!他真的帮助了很多人!

你可能感兴趣的:(Java,黑马程序员,张孝祥,enum)