您的位置:首页 > 职场人生

黑马程序员-一种不同张孝祥老师视频中交通灯管理系统的实现

2014-07-21 13:16 537 查看
----------------------
ASP.Net+Unity开发、.Net培训、期待与您交流! ----------------------

个人设计的另外一种关于张老师的交通灯管理系统的实现方法,前期的分析和张老师的没什么区别,就是在具体代码实现时候用的是我自己的代码,和张老师的代码还是有一点区别的,但在结果应该是没有区别吧,我也没有认真的测试,唯一的感触就是找bug花的时间是数倍于写代码的时间。

先说一下我的思路吧,在前期路径分析上和张老师的分析是一样的,但是就是再用面向对象的思想抽象出类的时候我和张老师的有一些不一样。

我抽象出了如下几个类:
Lamp: 很简单,就是封装了交通灯的颜色RED和GREEN两个枚举对象。

Lamp.java

package cn.itcast.mytraffic;

public enum Lamp {
RED,GREEN
}

Lampinfo:用来描述交通灯的这个对象,我想就是一个交通灯的这个类,在一个十字路口只能有一个,不能同时产生多个,所以我把这个类设计成了单例,同时它也应该有交通灯变换的时间(time)这个变量,也应该有两条由南到北(Route.N2S),由西到东(Route.W2E)的两条路(这样才能组成十字路口么),要设置时间,所以一定要有time的set和get方法。这个类,对外要展示的就是从南到北和从北到南这两条路的红绿灯的信息,所以我定义了一个图(lampinfo)的结构来把路径与灯棒定在一起。并对外值提供了get方法。

Lampinfo.java

package cn.itcast.mytraffic;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class Lampinfo {

//方向从北向南,从西向东
Route[] route = {Route.N2S,Route.W2E};
//数据结构怎么定义,代表不同的路况默认是北南方向绿,西东方向红
private Map<Route, Lamp> lampinfo = new HashMap<Route, Lamp>();
public Map<Route, Lamp> getLampinfo() {
return lampinfo;
}
//红绿灯的变换时间默认time是30
private int time;
public int getTime() {
return time;
}
public void setTime(int time) {
this.time = time;
}
private Lampinfo(){
this.time = 10;
//默认北南方向绿,西东方向红
lampinfo.put(route[0],Lamp.GREEN);
lampinfo.put(route[1], Lamp.RED);
System.out.println("南北方向为绿灯");
}
private static Lampinfo mylampinfo = new Lampinfo();
public static Lampinfo newinstance(){
return mylampinfo;
}
//启动一个线程来模拟在一定的时间下切换红绿灯的状态
//如N-S和S-N红,W-E,E-W绿,然后翻转。
//要用一个数据结构来保存两个状态
//{N-S,红},{W-E,绿}
//{N-S,绿},{W-E,红}
private synchronized void converLamp(){
//翻转交通灯的状态
if(lampinfo.get(route[0]) == Lamp.GREEN
&& lampinfo.get(route[1]) == Lamp.RED){
lampinfo.put(route[1],Lamp.GREEN);
lampinfo.put(route[0], Lamp.RED);
//System.out.println("从北向南应为:红,实际上:"+lampinfo.get(route[0]).toString());
//System.out.println("从西向东应为:绿,实际上:"+lampinfo.get(route[1]).toString());
System.out.println("西东方向为绿灯");
}else if(lampinfo.get(route[0]) == Lamp.RED && lampinfo.get(route[1]) == Lamp.GREEN) {
lampinfo.put(route[0],Lamp.GREEN);
lampinfo.put(route[1], Lamp.RED);
System.out.println("南北方向为绿灯");
}

}
public void Start(){
//每个time秒转换一次交通灯
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
new Runnable() {

@Override
public void run() {
converLamp();
}
},
10,
time,
TimeUnit.SECONDS);
}
}
Rote:这个类是一个枚举类,就是实现了12个方向的枚举对象,和Lamp类是一个性质的,相信大家都懂的,只不过我重写了tostring方法,让输出的信息更好看一些。

package cn.itcast.mytraffic;

public enum Route {
//定义12个方向
//右转,四个方向,不需要看红绿灯
N2W,E2N,W2S,S2E,
//左转,直行需要看红绿灯
//当N-S和S-N方向通畅时
//N-S方向直行,左转,S-N方向直行,左转
N2S,N2E,S2N,S2W,
/*
* 当W-E方向和E-W方向通畅时
* W-E方向直行,左转,E-W方向直行,左转
*/
W2E,W2N,E2W,E2S;
//以上共12中行驶路线
//重新实现tostring方法,用来输出实际的路线信息
public String toString() {
switch (this) {
case N2W:
return "北向西,右转";
case E2N:
return "东向北,右转";

case W2S:
return "西向南,右转";

case S2E:
return "南向东,右转";

case N2S:
return "北向南,直行";

case N2E:
return "北向东,左转";

case S2N:
return "南向北,直行";

case S2W:
return "南向西,左转";
case W2E:
return "西到东,直行";
case W2N:
return "西到北,左转";
case E2W:
return "东到西,直行";
case E2S:
return "东到南,左转";
default:
System.out.println("出错啦!!");
break;
}
return null;
};
}
Road:这个我和张老师的想法一样,或者说是在他的引导下,但在实现上我和张老师的有区别,Road这个类是要产生增加车和减少车的方法的,而且这个方法是动态,十字路口,十二个方向,在路上跑的每台车都要有自己的方向,所以我认为生成的车要有自己的方向。同时我用队列来实现车的增加和减少,也就避免了撞车的可能吧,因为队列不是有尾端插入,前段删除的性质嘛。
Road.java

package cn.itcast.mytraffic;

import java.util.LinkedList;
import java.util.Queue;
import java.util.Random;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class Road {

//N-S和S-N是绿灯的行驶车辆信息这里考虑用队列来实现,其好处是不用判断前面的车是否出去了,因为队列就是前端删除,后端插入。
//private List<Route> CarN2S = new ArrayList<Route>();
private Queue<Route> CarN2S = new LinkedList<>();
//W-E和E-W是绿灯的形式车辆信息
//private List<Route> CarW2E = new ArrayList<Route>();
private Queue<Route> CarW2E = new LinkedList<>();
//封装从N-S和S-N是绿灯时车辆所有可能的行驶方向
private Route[] routeN2S ={Route.N2S,Route.N2E,Route.S2N,Route.S2W,Route.N2W,Route.S2E,Route.W2S,Route.E2N};
//封装从W-E和E-W是绿等是车辆所有可能的形式方向
private Route[] routeW2E = {Route.W2E,Route.W2N,Route.E2N,Route.E2S,Route.E2W,Route.W2S,Route.S2E,Route.N2W};
//用队列的方式实现车的添加和减少
public Road(){
//从N-S方向先随机生成5辆车
for(int i=0;i<5;i++){
CarN2S.offer(routeN2S[new Random().nextInt(7)]);
}
//从W-E方向也随机生成5辆车
for(int i=0;i<5;i++){
CarW2E.offer(routeW2E[new Random().nextInt(7)]);
}
}
private  void addCar(){
//每1秒路上增加1辆车

b3a2

if(!CarN2S.offer(routeN2S[new Random().nextInt(7)])){
System.out.println("车辆增加异常!");
}

//每1秒路上增加一辆车
if(!CarW2E.offer(routeW2E[new Random().nextInt(7)])){
System.out.println("车辆增加异常!");
}
//System.out.println("进入addCar了");
}
public void Start(){
//创建一个可以调度线程池用来分别添加两个方向的车
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
//这么做线程应该发生了死锁?不是死锁,无法插入元素了,数组越界了,小bug找了好久。
addCar();
//	System.out.println("从addCar出来了");
}
},
1,
2,
TimeUnit.SECONDS);
}
public Route getCarN2S() {
return CarN2S.poll();
}
public Route getCarW2E() {
return CarW2E.poll();
}

}

TrafficControl:这个类是核心,其他的类都是为它服务的,因为这个系统的调度在这里。这里我就实现了一个schedule方法,根据Lampinfo类的lampinfo.getLampinfo()方法来获取当前路口的颜色,如果为绿色,则调度车辆运行。
TrafficControl.java

package cn.itcast.mytraffic;

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

public class TrafficControl {

/*private Lamp[] lamps={Lamp.RED,Lamp.GREEN};*/
private Road road;
private Lampinfo lampinfo;

public TrafficControl(Road road,Lampinfo lampinfo){
this.road = road;
this.lampinfo = lampinfo;
}
//根据灯的信息来调度不同路线上的车辆
public synchronized void schedule(){
//判断当前的红绿灯颜色
Map<Route, Lamp> lamp =  lampinfo.getLampinfo();
//从南向北行驶的所有车辆应该获得该方向的灯的颜色
//绿灯,可以行驶
if(lamp.get(Route.N2S) == Lamp.GREEN){
//线程在这里面等待获得队列删除后返回的元素,程序在这里面发生了死锁?
Route carinfN2S= road.getCarN2S();
if(carinfN2S == null){
System.out.println("没车了!!");
}else {
System.out.println("从南向北方向畅通"+carinfN2S.toString() + "正在行驶");
}

}else if (lamp.get(Route.W2E) == Lamp.GREEN) {
//线程在这里面等待获得队列删除后返回的元素,程序在这里面发生了死锁?

Route carinfW2E = road.getCarW2E();
if(carinfW2E == null){
System.out.println("没车了!!");
}else{
System.out.println("从西向东方向畅通" + carinfW2E.toString() + "正在行驶");
}

}
}
public void Start(){
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
new Runnable() {
@Override
public void run() {
schedule();
}
},
2,
1,
TimeUnit.SECONDS);
}

}
StartMain类是一个启动类,无需多解释了。

package cn.itcast.mytraffic;

public class StartMain {
public static void main(String[] args) {
Road road = new Road();
Lampinfo lampinfo = Lampinfo.newinstance();
TrafficControl trafficControl = new TrafficControl(road, lampinfo);
//开启交通灯
lampinfo.Start();
//路上开始不断的增加车辆
road.Start();
//开始调度
trafficControl.Start();
}
}
运行结果:

南北方向为绿灯

从南向北方向畅通南向北,直行正在行驶

从南向北方向畅通北向南,直行正在行驶

从南向北方向畅通南向北,直行正在行驶

从南向北方向畅通南向东,右转正在行驶

从南向北方向畅通南向东,右转正在行驶

从南向北方向畅通南向西,左转正在行驶

从南向北方向畅通南向东,右转正在行驶

从南向北方向畅通南向东,右转正在行驶

西东方向为绿灯

从西向东方向畅通西到东,直行正在行驶

从西向东方向畅通东到西,直行正在行驶

从西向东方向畅通东向北,右转正在行驶

从西向东方向畅通东到南,左转正在行驶

从西向东方向畅通西到东,直行正在行驶

从西向东方向畅通东到南,左转正在行驶

从西向东方向畅通东向北,右转正在行驶

从西向东方向畅通东到南,左转正在行驶

从西向东方向畅通东向北,右转正在行驶

从西向东方向畅通东向北,右转正在行驶

南北方向为绿灯

从南向北方向畅通南向北,直行正在行驶

从南向北方向畅通西向南,右转正在行驶

从南向北方向畅通南向北,直行正在行驶

从南向北方向畅通南向东,右转正在行驶

从南向北方向畅通南向东,右转正在行驶

从南向北方向畅通北向西,右转正在行驶

从南向北方向畅通北向南,直行正在行驶

从南向北方向畅通北向东,左转正在行驶

从南向北方向畅通西向南,右转正在行驶

从南向北方向畅通西向南,右转正在行驶

西东方向为绿灯

从西向东方向畅通东到西,直行正在行驶

从西向东方向畅通东向北,右转正在行驶

从西向东方向畅通西向南,右转正在行驶

从西向东方向畅通南向东,右转正在行驶

从西向东方向畅通南向东,右转正在行驶

从西向东方向畅通东向北,右转正在行驶

从西向东方向畅通东到西,直行正在行驶

从西向东方向畅通东到南,左转正在行驶

从西向东方向畅通东向北,右转正在行驶

从西向东方向畅通西到东,直行正在行驶

南北方向为绿灯

从南向北方向畅通西向南,右转正在行驶

从南向北方向畅通北向东,左转正在行驶

----------------------
ASP.Net+Unity开发、.Net培训、期待与您交流! ----------------------详细请查看:www.itheima.com
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java 对象 软件 设计