黑马程序员-交通灯

时间:2023-02-17 19:04:29

---------------------- android培训,java培训、期待与您交流! ----------------------

 

交通灯:

根据现实生活中的交通灯分析,交通灯的路线可以分为12,12条路线可以分成相同的4, 每一组中的路线分别是: 直行 ,左转 , 和右转. 面对面的交通灯的亮灯规则相同 , 也就是说: 南面直行的灯变绿灯, 北面直行的也是绿灯 ; 当直行结束之后 , 南北左转灯变绿灯, 南北的绿灯结束后 , 东西面按照相同的规则执行. 值得注意的是,交通灯中,没有右转灯,所以可以假设右转是常绿灯.

规则简单介绍:

1.       南北直行

2.       南北左转

3.       东西直行

4.       东西左转

 

面向对象分析:

在交通灯这道题中涉及到, 灯的控制器, 路线, 车辆. 灯有红, 绿, 黄三种颜色; 灯的控制器控制颜色的改变; 路线有直行,左转,右转三种情况; 因为这题不需要考虑车辆通过红绿灯的过程,只需要知道有一辆车通过了,并且车辆是在路线上通行的,所以车辆不是对象, 而是路线中的一部分. 但是需要注意的是, 当绿灯亮起的时候, 并不是所有的车都可以通行, 而是只有最前面的那一辆才能通行, 而且车是有增有减的, 所以应该定义一个集合来存储车辆

 

 

设计思路:

:

       总共有12盏灯,并且这12盏灯是固定不变的,每一盏灯都是一个对象,并且每一盏灯都要有一个状态红或者绿”, 并且每个灯都要有一个变红和变绿的方法. 所以应该把灯用枚举来表示.

虽然有12盏灯, 显得很多, 但是其实只有4盏灯是有逻辑的, 可以选择à;

à西 ; 西à ; 西à来作为这4盏灯,与之相对的4盏灯的状态和这4盏灯的是一致的. 还有4盏灯是右转的, 实际生活中没有右转灯, 所以这4盏右转灯可以假定为常绿灯.

 

       灯的类中只有三个属性 : boolean lighted---(是否是绿灯) , String opposite---(与之相反的灯) , String next ---(下一盏灯)

       灯只有两个方法:  void light()---点亮自己这盏灯和与之对应的反方向的灯

Lamp nextLamp()---当本身变成红灯的时候,把与之对应的灯变红,并且把下一盏灯变绿

 

 

publicenum Lamp {

   

    /* 4盏有逻辑的灯(oppositenext要是String类型,因为如果是Lamp类型,

     那么在调用的时候,oppositenext对象还没有创建,在使用到的时候通过枚举的valueOf方法把字符串转换成相应的Lamp类型)*/

    S2N(false,"N2S","S2W"),S2W(false,"N2E","E2W"),E2W(false,"W2E","E2S"),E2S(false,"W2N","S2N"),

   

    //4盏与之对应的灯(这里的oppositenext为空是因为这样做就保证light()方法和blackOut()不会变成死循环)

    N2S(false,"null","null"),N2E(false,"null","null"),W2E(false,"null","null"),W2N(false,"null","null"),

   

    //4盏右转的灯

    S2E(true,"null","null"),E2N(true,"null","null"),N2W(true,"null","null"),W2S(true,"null","null");

   

    //当前是否绿灯

    privatebooleanlighting;

   

    //对应的灯的名字

    private String opposite;

   

    //下一盏灯的名字

    private String  next;

 

    private Lamp(boolean lighting, String opposite, String next) {

       this.lighting = lighting;

       this.opposite = opposite;

       this.next = next;

    }

   

    publicboolean isLight(){

       returnlighting;

    }

   

   

    //当灯变绿的的时候,对应的灯也变绿

    publicvoid light(){

       this.lighting=true;                              //设置为绿灯

       if(opposite!=null){        

           Lamp.valueOf(Lamp.this.name()).isLight();     //把对应的灯的字符串转变成枚举类型,并得到灯的状态   

       }

       System.out.println(name() + " lamp is green,下面总共应该有6个方向能看到汽车穿过!");

    }

   

    //当灯变红的时候,对应的灯也变红,并且下一盏灯变绿 

    public Lamp blackOut(){

       this.lighting=false;

       if(opposite!=null){

           Lamp.valueOf(next).isLight();         

       }

             

       Lamp nextLamp=null;                              //定义下一盏灯

       if(next!=null){                                  //如果有下一盏灯

           nextLamp=Lamp.valueOf(next);

           nextLamp.light();                 

       }

       return nextLamp;           

    }

}

 

 

 

灯控制器:

       灯控制器中有一个属性: Lamp currentLamp---(当前的灯)

       在灯控制器中先指定一盏灯为绿灯 , 然后通过计时器来给绿灯计时, 当时间到的时候,把当前绿灯变红, 然后返回下一个绿灯.

 

import java.util.concurrent.*;

 

 

 

publicclass LampController {

 

    private Lamp  currentLamp;   //当前灯

    LampController(){

       currentLamp=Lamp.S2N;           //指定一个当前灯

       currentLamp.oppoLamp();         //把当前灯变绿灯

      

       ScheduledExecutorService timer=Executors.newScheduledThreadPool(1);

       timer.scheduleAtFixedRate(new Runnable(){

 

           @Override

           publicvoid run() {

              // TODO Auto-generated method stub

              currentLamp=currentLamp.blackOut();

           }         

       },

       10, 10,

       TimeUnit.SECONDS);             

    }

   

}

 

 

 

路线:

车辆是在路线上,所以要在路线的构造函数上初始化一些车辆,而这些车辆不可能一瞬间就出现了,所以应该要有间隔时间.

路线还有一个方法来移除车辆,当绿灯的时候,会每个一定时间移除车辆集合中的第一个辆车

/*

 * 车辆是在路线上,所以要在路线的构造函数上初始化一些车辆,而这些车辆不可能一瞬间就出现了,所以应该要有间隔时间.

  路线还有一个方法来移除车辆,当绿灯的时候,会每个一定时间移除车辆集合中的第一个辆车

 * */

 

import java.util.*;

import java.util.concurrent.Executor;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import java.util.concurrent.ScheduledExecutorService;

import java.util.concurrent.TimeUnit;

 

publicclass Road {

    private List<String>  vehicles =new ArrayList<String> ();   //创建一个集合,存放车辆

    private String name=null;   //路线的名字

    Road(){

       this.name=name;

       //创建一个线程池

       ExecutorService pool=Executors.newSingleThreadExecutor();  

       pool.execute(new Runnable(){

           @Override

           publicvoid run() {

              // TODO Auto-generated method stub    

              //产生50辆车

              for (int i = 0; i < 50; i++) {               

                  try {

//随机睡眠 

                     Thread.sleep((new Random().nextInt(10)+1)*1000);

                     vehicles.add(Road.this.name+"_"+i);

                  } catch (Exception e) {

                     // TODO: handle exception

                     e.printStackTrace();

                  }

              }

           }

       });

      

       //一个计时器,每一秒钟就移除一辆车

       ScheduledExecutorService timer=Executors.newScheduledThreadPool(1);       //创建一个计时器,接收一个线程池

       timer.scheduleAtFixedRate(new Runnable(){                         

 

           @Override

           publicvoid run() {

              // TODO Auto-generated method stub

              if(vehicles.size()>0){      //如果有车

                  boolean lighted=Lamp.valueOf(Road.this.name).isLight();     //得到路线上灯的状态

                  if(lighted){

                     System.out.println(vehicles.remove(0)+"开走啦!");                  

                  }                

              }

           }         

       },

       1,                   //一秒中后做一件事

       1,                   //1秒再做下一次

       TimeUnit.SECONDS);       //时间的单位

    }                          

}

 

 

主函数:

在主函数中,要创建12条路线的对象,可以使用循环.并且要创建一个灯控制器.

 

publicclass MainClass {

    publicstaticvoid main(String[] args) {

    String[]lamp={"S2N","S2W","E2W","E2S","N2S","N2E","W2E","W2N","S2E","E2N","N2W","W2S"    };//初始化路线

       //创建路线

       for (int i = 0; i < lamp.length; i++) {

           new Road(lamp[i]);

       }  

       new LampController();

    }

}

 

 

总结:

在学习交通灯控制系统的过程中大量用到jdk1.5的新特性: 枚举. 使用枚举极大的简化了开发难度. 并且还复习了内部类要访问外部类的成员,需要用外部类名.this.成员名的方法, 除此之外,还学到了使用计时器: ScheduledExecutorService.

在学习的过程中,通过老师的讲解和一步一步的实践, 对面向对象的设计思想有了更深刻的认识, 受益匪浅.

 

 

---------------------- android培训,java培训、期待与您交流! ----------------------

详细请查看
http://edu.csdn.net/heima