黑马程序员-java交通灯管理系统

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

张孝祥老师的例子---交通灯管理系统,它的需求如下:

  异步随机生成按照各个路线行驶的车辆。
例如:
       由南向而来去往北向的车辆 ---- 直行车辆
       由西向而来去往南向的车辆 ---- 右转车辆
       由东向而来去往南向的车辆 ---- 左转车辆
       。。。

 信号灯忽略黄灯,只考虑红灯和绿灯。
 应考虑左转车辆控制信号灯,右转车辆不受信号灯控制。
 具体信号灯控制逻辑与现实生活中普通交通灯控制逻辑相同,不考虑特殊情况下的控制逻辑。
注:南北向车辆与东西向车辆交替放行,同方向等待车辆应先放行直行车辆而后放行左转车辆。

  1.  每辆车通过路口时间为1秒(提示:可通过线程Sleep的方式模拟)。
  2.  随机生成车辆时间间隔以及红绿灯交换时间间隔自定,可以设置。
  3.  不要求实现GUI,只考虑系统逻辑实现,可通过Log方式展现程序运行结果

张老师共用四个java类 Lamp.java  LampController.java   MainClass.java  Road.java  来实现。

现在先说说Lamp类。
1.  Lamp类表示交通灯,有属性:亮(绿)或不亮(红),每个交通灯有变亮和变黑的方法。一个路口,有三种前进可能:直行、转左、转右,十字路有四个路口,故共有3*4=12条路线,所以,系统中总共要产生12个交通灯。右拐弯的路线本来不受灯的控制,但是为了让程序采用统一的处理方式,故假设有四个右拐弯的灯,这些灯为常亮(常绿)状态。
2.  其他8条路线的灯,它们是两两成对的,可以归为4组,所以,在编程处理时,只要从这4组中各取出一个灯,对这4个灯依次轮询变亮,与这4个灯方向对应的灯则随之一同变化,因此Lamp类中要有一个变量来记住自己相反方向的灯,在一个Lamp对象的变亮和变黑方法中,将对应方向的灯也变亮和变黑。每个灯变黑时,都伴随者下一个灯的变亮,Lamp类中还用一个变量来记住自己的下一个灯。
3. Lamp类对象的数量固定,意义明确,所以适合用枚举来实现。 亮灭状态用lighted 表示,选用S2N、S2W、E2W、E2N这四个方向上的Lamp对象依次轮询变亮,对象中还要有一个opposite  来表示它们相反方向的灯,再用一个next 来表示此灯变亮后的下一个变亮的灯。其他方向上的Lamp对象的next 和opposite 属性设置为null即可,并且"N2S","N2E","W2E","W2N"这四个方向上的 next 和opposite 属性必须设置为null,以防止light和blackOut 互相调用,进入死循环。 
[java] view plaincopy
  1. public enum Lamp {  
  2.     /*每个枚举元素各表示一个方向的控制灯*/     
  3.     S2N("N2S","S2W",false),S2W("N2E","E2W",false),E2W("W2E","E2S",false),E2S("W2N","S2N",false),  
  4.     /*下面元素表示与上面的元素的相反方向的灯,它们的“相反方向灯”和“下一个灯”应忽略不计!*/  
  5.     N2S(null,null,false),N2E(null,null,false),W2E(null,null,false),W2N(null,null,false),  
  6.     /*由南向东和由西向北等右拐弯的灯不受红绿灯的控制,所以,可以假想它们总是绿灯*/  
  7.     S2E(null,null,true),E2N(null,null,true),N2W(null,null,true),W2S(null,null,true);  
  8.       
  9.     private Lamp(String opposite,String next,boolean lighted){  
  10.         this.opposite = opposite;  
  11.         this.next = next;  
  12.         this.lighted = lighted;  
  13.     }  
  14.   
  15.     /*当前灯是否为绿*/   
  16.     private boolean lighted;  
  17.     /*与当前灯同时为绿的对应方向*/     
  18.     private String opposite;  
  19.     /*当前灯变红时下一个变绿的灯*/     
  20.     private String next;  
  21.     public boolean isLighted(){  
  22.         return lighted;  
  23.     }  
  24.       
  25.     /** 
  26.      * 某个灯变绿时,它对应方向的灯也要变绿 
  27.      */   
  28.     public void light(){  
  29.         this.lighted = true;  
  30.         if(opposite != null){  
  31.             Lamp.valueOf(opposite).light();  
  32.         }  
  33.         System.out.println(name() + " lamp is green,下面总共应该有6个方向能看到汽车穿过!");        
  34.     }  
  35.       
  36.     /** 
  37.      * 某个灯变红时,对应方向的灯也要变红,并且下一个方向的灯要变绿 
  38.      * @return 下一个要变绿的灯 
  39.      */   
  40.     public Lamp blackOut(){  
  41.         this.lighted = false;  
  42.         if(opposite != null){  
  43.             Lamp.valueOf(opposite).blackOut();  
  44.         }         
  45.           
  46.         Lamp nextLamp= null;  
  47.         if(next != null){  
  48.             nextLamp = Lamp.valueOf(next);  
  49.             System.out.println("绿灯从" + name() + "-------->切换为" + next);            
  50.             nextLamp.light();  
  51.         }  
  52.         return nextLamp;  
  53.     }  
  54. }  
  •  Lamp就是一枚举,里面有12个对象,每个对象有三个属性。假如将opposite 属性也定义为Lamp,会成为Lamp嵌套Lamp,不行的。这里的属性都用String,那个表示亮灭的当然用布尔了。
  • 枚举Lamp 有三个方法,只有blackOut() 复杂些。它实现两个功能:1、将opposite 的灯变红,2、next 的灯变绿,最后返回 next 。
  • S2N("N2S","S2W",false) 实质是调用了Lamp(String opposite,String next,boolean lighted) 构造方法,.相当于 Lamp.S2N.opposite ="N2S",……,对带构造方法的枚举不了解的,可参考黑马视频 “Java基础加强_实现带有构造方法的枚举”。
  •  Road类
    每条路线上都会出现多辆车,路线上要随机增加新的车,在灯绿期间还要每秒钟减少一辆车。
    • 设计一个Road类来表示路线,每个Road对象代表一条路线,总共有12条路线,即系统中总共要产生12个Road实例对象。
    • 每条路线上随机增加新的车辆,增加到一个集合中保存。
    • 每条路线每隔一秒都会检查控制本路线的灯是否为绿,是则将本路线保存车的集合中的第一辆车移除,即表示车穿过了路口。
    • 每个Road对象都有一个name成员变量来代表方向,有一个vehicles成员变量来代表方向上的车辆集合。
    • 在Road对象的构造方法中启动一个线程每隔一个随机的时间向vehicles集合中增加一辆车(用一个“路线名_id”形式的字符串进行表示)。
    • 在Road对象的构造方法中启动一个定时器,每隔一秒检查该方向上的灯是否为绿,是则打印车辆集合和将集合中的第一辆车移除掉。
    [java] view plaincopy
    1. import java.util.ArrayList;  
    2. import java.util.List;  
    3. import java.util.Random;  
    4. import java.util.concurrent.ExecutorService;  
    5. import java.util.concurrent.Executors;  
    6. import java.util.concurrent.ScheduledExecutorService;  
    7. import java.util.concurrent.TimeUnit;  
    8.   
    9. /** 
    10.  * 每个Road对象代表一条路线,总共有12条路线,即系统中总共要产生12个Road实例对象。 
    11.  * 每条路线上随机增加新的车辆,增加到一个集合中保存。 
    12.  * 每条路线每隔一秒都会检查控制本路线的灯是否为绿,是则将本路线保存车的集合中的第一辆车移除,即表示车穿过了路口。 
    13.  * @author 张孝祥 www.it315.org 
    14.  * 
    15.  */  
    16. public class Road {  
    17.     private List<String> vechicles = new ArrayList<String>();  
    18.       
    19.     private String name =null;  
    20.     public Road(String name){  
    21.         this.name = name;  
    22.           
    23.         //模拟车辆不断随机上路的过程       
    24.         ExecutorService pool = Executors.newSingleThreadExecutor();  
    25.         pool.execute(new Runnable(){  
    26.             public void run(){  
    27.                 for(int i=1;i<1000;i++){  
    28.                     try {  
    29.                         Thread.sleep((new Random().nextInt(10) + 1) * 1000);  
    30.                     } catch (InterruptedException e) {  
    31.                         e.printStackTrace();  
    32.                     }  
    33.                     vechicles.add(Road.this.name + "_" + i);  
    34.                 }                 
    35.             }  
    36.               
    37.         });  
    38.           
    39.         //每隔一秒检查对应的灯是否为绿,是则放行一辆车          
    40.         ScheduledExecutorService timer =  Executors.newScheduledThreadPool(1);  
    41.         timer.scheduleAtFixedRate(  
    42.                 new Runnable(){  
    43.                     public void run(){  
    44.                         if(vechicles.size()>0){  
    45.                             boolean lighted = Lamp.valueOf(Road.this.name).isLighted();  
    46.                             if(lighted){  
    47.                                 System.out.println(vechicles.remove(0) + " is traversing !");  
    48.                             }  
    49.                         }  
    50.                           
    51.                     }  
    52.                 },  
    53.                 1,  
    54.                 1,  
    55.                 TimeUnit.SECONDS);        
    56.     }  
    57. }  
    1. 这里直接贴上了张老师的 Road 代码,包括一些说明。即使是说明,实在没多少可改动,增删的,所以这里作了次“传送门”。
    2. 当然,代码可以作些解释,它是用了线程池的技术,Collections 是Java5 新增的,用于并行处理,比之前的wait()、notify()和synchronized等,方便安全得多。
    3. Executor 是具体Runnable任务的执行者,ExecutorService 是线程池管理者,用 ScheduledExecutorService 定时调度线程池。程序中 newScheduledThreadPool(1) --- 创建了一个线程池,里面却只有1个线程,但随后用scheduleAtFixedRate 方法创建一直定期运行的任务,程序中,初始延迟(首次启用)是1秒,后期延迟周期也是1秒。
    4. 多线程方面,可参考 毕向东的多线程 视频,足足有25个呵;线程池方面,可参考 张孝祥-Java多线程与并发库高级应用 视频。

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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值