交通灯管理系统

来源:互联网 发布:安兔兔评测软件 编辑:程序博客网 时间:2024/05/29 16:32


首先要做需求分析,然后设计这个项目的结构和功能。具体来说,就是这个项目应该包含哪几个类,这些类与类之间的联系,以及这些类中分别需要实现的方法。要弄明白这些不是一件容易的事,坦白说,我自己想一天也未必能想明白。呵呵,这就是能力啊。张老师把这些都分析的非常清楚:

1.总共有12条路线,为了统一编程模型,可以假设每条路线都有一个红绿灯对其进行控制,右转弯的4条路线的控制灯可以假设称为常绿状态,另外,其他的8条线路是两两成对的,可以归为4组,所以,程序只需考虑1S2N 2S2W 3E2W 4E2S 这4条路线的控制灯的切换顺序,这4条路线相反方向的路线的控制灯跟随这4条路线切换,不必额外考虑。

 

2.为了使思路更加清晰,开始只考虑从南面开来的车辆:

1)右转(S2E)的信号灯永远是绿灯;

2)同方向等待车辆应先放行直行车辆(S2N)而后放行左转车辆(S2W)。

 

3.面向对象的分析与设计:

1)初步设想一下有哪些对象:红绿灯,红绿灯的控制系统,汽车,路线。

2)汽车看到自己所在路线对应的灯绿了就穿过路口吗?不是,还需要看前面是否有车,看前面是否有车,该问哪个对象呢?该问路,路中存储着车辆的集合,显然路上就应该有增加车辆和减少车辆的方法了。(面向对象设计把握一个重要的经验:谁拥有数据,谁就对外提供操作这些数据的方法。)再看题目,我们这里并不要体现车辆移动的过程,只是捕捉出车辆穿过路口的过程,也就是捕捉路上减少一辆车的过程,所以,这个车并不需要单独设计成为一个对象,用一个字符串表示就可以了。在1中初步设想的对象就减少了一个。这个项目只需要3个对象即可。

3)在这个十字路口,有且仅有12盏红绿灯,因此红绿灯可以用枚举来实现。其中右转的四盏灯常绿,剩下的八盏灯可以分为4组。因此只需要考虑4盏灯的红绿变化。

 

4.跟随老师一起编写代码:

1)Road类:

 public class Road{ private List<String> vehicles = new ArrayList<String>(); //用这个List来装载这条路上的车  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 = 0; i < 1000; i++)    {     try     {      Thread.sleep((new Random().nextInt(10)+1) * 1000);     } catch (InterruptedException e)     {      e.printStackTrace();     }//     vehicles.add(name + "_" + i);这样写编译会报错,因为这里访问的是这个构造方法里的局部变量。在匿名内部类里访问局部变量,这个局部变量必须用final修饰符修饰。所以这里有两种改法:1.加final修饰符,2.在这里访问外部类的成员变量。     vehicles.add(Road.this.name + "_" + i);  //访问外部类的成员变量。    }   }  });    //启动一个定时器。这种方法我以前也没用过。额,这种方法的确比TimeTask什么的好用多了。  ScheduledExecutorService timer = Executors.newScheduledThreadPool(1);  timer.scheduleAtFixedRate(   //这个方法需要四个参数    new Runnable()          //参数1:任务。如果是绿灯,并且路上有车,就移走一辆车    {     @Override     public void run()     {      if (vehicles.size()>0)      {       boolean lighted = Lamp.valueOf(Road.this.name).isLighted();//       if (true == lighted) 这行代码的不妥之处在于画蛇添足       if (lighted)       {        System.out.println(vehicles.remove(0) + "is traversing ! ");       }      }     }    },                        1,                   //参数2:多少时间后开始执行任务    1,                   //参数3:每隔多少时间执行一次任务    TimeUnit.SECONDS     //参数4:前面这两个时间的单位    ); }}

2.Lamp枚举

package com.isoftstone.interview.traffic;public enum Lamp{ S2N("N2S","S2W",false),S2W("N2E","E2W",false),E2W("W2E","E2S",false),E2S("W2N","S2N",false), //有业务逻辑的4个灯 N2S(null,null,false)  ,N2E(null,null,false)  ,W2E(null,null,false)  ,W2N(null,null,false)  , //和上面一一对应的4个灯 S2E(null,null,true)   ,E2N(null,null,true)   ,N2W(null,null,true)   ,W2S(null,null,true)   ; //常绿的4个灯  private boolean lighted; //用来表示灯的状态。true为绿灯,false为红灯 private String opposite;//这里要把相对应的Lamp用字符串代替,是因为S2N(N2S)这种写法可能会报错,Cannot reference a field before it is defined. 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(name()+" lamp is green ,下面总共应该有6个方向能看到汽车穿过 !"); //这六个方向是指:当前路线,//当前路线的对应路线,以及4个常绿路线。 } // 让当前灯变红的方法,同时检查当前灯有没有对应灯,若有,需将对应灯也变红。然后,将当前灯的下一盏灯变绿。 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()+" ---------->切换为:"+next);   nextLamp.light();  }    return nextLamp; }}

3.红绿灯的控制系统:LampController类

public class LampController{ private Lamp currentLamp;  public LampController() {  currentLamp = Lamp.S2N; //最开始设定S2N这个灯是绿的  currentLamp.light();    ScheduledExecutorService timer = Executors.newScheduledThreadPool(1);  timer.scheduleAtFixedRate(    new Runnable() //每隔10s将当前灯变暗,同时将currentLamp变为下一盏灯。    {     @Override     public void run()     {      System.out.println("灯控定时器");      currentLamp = currentLamp.blackOut();     }    },    2,    2,    TimeUnit.SECONDS    ); }}

4.项目的主类:MainClass

public class MainClass{ public static void main(String[] args) {  //new出12条路线,再加一个灯控制器,就可以模拟一个十字路口了。  String[] directions = new String[]{    "S2N","S2W","E2W","E2S","N2S","N2E","W2E","W2N","S2E","E2N","N2W","W2S"  };  for (int i = 0; i < directions.length; i++)  {   new Road(directions[i]);  }    new LampController();    //红绿灯控制器 }}

看完第一遍视屏,感觉就像看天书一样,云里雾里的,没明白啥意思,看第二遍的时候,就有感觉了,但是还有一些不明白的地方,再看一遍的时候,就明白了



原创粉丝点击