开发者社区> 字节卷动> 正文

我的Java开发学习之旅------>交通灯管理系统

简介: 1.交通灯管理系统的项目需求 模拟实现十字路口的交通灯管理系统逻辑,具体需求如下: Ø         异步随机生成按照各个路线行驶的车辆。 例如: 由南向而来去往北向的车辆 ---- 直行车辆        由西向而来去往南向的车辆 ---- 右转车辆        由东向而来去往南向的车辆 ---- 左转车辆        。
+关注继续查看

1.交通灯管理系统的项目需求

模拟实现十字路口的交通灯管理系统逻辑,具体需求如下:

Ø         异步随机生成按照各个路线行驶的车辆。

例如:

由南向而来去往北向的车辆 ---- 直行车辆

       由西向而来去往南向的车辆 ---- 右转车辆

       由东向而来去往南向的车辆 ---- 左转车辆

       。。。

Ø         信号灯忽略黄灯,只考虑红灯和绿灯。

Ø         应考虑左转车辆控制信号灯,右转车辆不受信号灯控制。

Ø         具体信号灯控制逻辑与现实生活中普通交通灯控制逻辑相同,不考虑特殊情况下的控制逻辑。

注:南北向车辆与东西向车辆交替放行,同方向等待车辆应先放行直行车辆而后放行左转车辆。

Ø         每辆车通过路口时间为1秒(提示:可通过线程Sleep的方式模拟)。

Ø         随机生成车辆时间间隔以及红绿灯交换时间间隔自定,可以设置。

Ø         不要求实现GUI,只考虑系统逻辑实现,可通过Log方式展现程序运行结果。

2.切不可空想,一定要画图

画图非常有助于理解和分析问题,你还有比画图更好的办法吗?

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

具体分析及代码编写如下:

/**

*每个Lamp元素代表一个方向上的灯,总共有12个方向,所有总共有12Lamp元素。

*有如下一些方向上的灯,每两个形成一组,一组灯同时变绿或变红,所以,

*程序代码只需要控制每组灯中的一个灯即可:

* s2n,n2s  

* s2w,n2e

* e2w,w2e

* e2s,w2n

* s2e,n2w

* e2n,w2s

*上面最后两行的灯是虚拟的,由于从南向东和从西向北、以及它们的对应方向不受红绿灯的控制,所以,可以假想它们总是绿灯。

*/

/*每个枚举元素各表示一个方向的控制灯*/

 S2N("N2S","S2W",false),S2W("E2N","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),N2W(null,null,true),W2S(null,null,true),E2N(null,null,true);

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

l     每条路线上都会出现多辆车,路线上要随机增加新的车,在灯绿期间还要每秒钟减少一辆车。

Ø     设计一个Road类来表示路线,每个Road对象代表一条路线,总共有12条路线,即系统中总共要产生12个Road实例对象。

Ø     每条路线上随机增加新的车辆,增加到一个集合中保存。

Ø     每条路线每隔一秒都会检查控制本路线的灯是否为绿,是则将本路线保存车的集合中的第一辆车移除,即表示车穿过了路口。

l     每条路线每隔一秒都会检查控制本路线的灯是否为绿,一个灯由绿变红时,应该将下一个方向的灯变绿。

Ø     设计一个Lamp类来表示一个交通灯,每个交通灯都维护一个状态:亮(绿)或不亮(红),每个交通灯要有变亮和变黑的方法,并且能返回自己的亮黑状态。

Ø     总共有12条路线,所以,系统中总共要产生12个交通灯。右拐弯的路线本来不受灯的控制,但是为了让程序采用统一的处理方式,故假设出有四个右拐弯的灯,只是这些灯为常亮状态,即永远不变黑(红)。

Ø     除了右拐弯方向的其他8条路线的灯,它们是两两成对的,可以归为4组,所以,在编程处理时,只要从这4组中各取出一个灯,对这4个灯依次轮询变亮,与这4个灯方向对应的灯则随之一同变化,因此Lamp类中要有一个变量来记住自己相反方向的灯,在一个Lamp对象的变亮和变黑方法中,将对应方向的灯也变亮和变黑。每个灯变黑时,都伴随者下一个灯的变亮,Lamp类中还用一个变量来记住自己的下一个灯。

Ø     无论在程序的什么地方去获得某个方向的灯时,每次获得的都是同一个实例对象,所以Lamp类改用枚举来做显然具有很大的方便性,永远都只有代表12个方向的灯的实例对象。

Ø     设计一个LampController类,它定时让当前的绿灯变红。

  面向对象讲解与窍门:

我们初步设想一下有哪些对象:红绿灯,红绿灯的控制系统,汽车,路线。汽车看到自己所在路线对应的灯绿了就穿过路口吗?不是,还需要看其前面是否有车,看前面是否有车,该问哪个对象呢?该问路,路中存储着车辆的集合,显然路上就应该有增加车辆和减少车辆的方法了。再看题目,我们这里并不要体现车辆移动的过程,只是捕捉出车辆穿过路口的过程,也就是捕捉路上减少一辆车的过程,所以,这个车并不需要单独设计成为一个对象,用一个字符串表示就可以了。

面向对象设计把握一个重要的经验:谁拥有数据,谁就对外提供操作这些数据的方法。再牢牢掌握几个典型的案例就可以了人在黑板上画圆,列车司机紧急刹车,你把门关上了等

4.代码实现简介(主要类分析)

l     Road类的编写

每个Road对象都有一个name成员变量来代表方向,有一个vehicles成员变量来代表方向上的车辆集合。

在Road对象的构造方法中启动一个线程每隔一个随机的时间向vehicles集合中增加一辆车(用一个“路线名_id”形式的字符串进行表示)。

在Road对象的构造方法中启动一个定时器,每隔一秒检查该方向上的灯是否为绿,是则打印车辆集合和将集合中的第一辆车移除掉。

l     Lamp类的编写

系统中有12个方向上的灯,在程序的其他地方要根据灯的名称就可以获得对应的灯的实例对象,综合这些因素,将Lamp类用java5中的枚举形式定义更为简单。

每个Lamp对象中的亮黑状态用lighted变量表示,选用S2N、S2W、E2W、E2N这四个方向上的Lamp对象依次轮询变亮,Lamp对象中还要有一个oppositeLampName变量来表示它们相反方向的灯,再用一个nextLampName变量来表示此灯变亮后的下一个变亮的灯。这三个变量用构造方法的形式进行赋值,因为枚举元素必须在定义之后引用,所以无法再构造方法中彼此相互引用,所以,相反方向和下一个方向的灯用字符串形式表示。

增加让Lamp变亮和变黑的方法:light和blackOut,对于S2N、S2W、E2W、E2N这四个方向上的Lamp对象,这两个方法内部要让相反方向的灯随之变亮和变黑,blackOut方法还要让下一个灯变亮。

除了S2N、S2W、E2W、E2N这四个方向上的Lamp对象之外,其他方向上的Lamp对象的nextLampName和oppositeLampName属性设置为null即可,并且S2N、S2W、E2W、E2N这四个方向上的Lamp对象的nextLampName和oppositeLampName属性必须设置为null,以便防止light和blackOut进入死循环。

l     LampController类的编写

整个系统中只能有一套交通灯控制系统,所以,LampController类最好是设计成单例(即一个私有变量一个对外构造方法)。

LampController构造方法中要设定第一个为绿的灯。

LampController对象的start方法中将当前灯变绿,然后启动一个定时器,每隔10秒将当前灯变红和将下一个灯变绿。

l     MainClass类的编写

用for循环创建出代表12条路线的对象。

接着再获得LampController对象并调用其start方法。

 

 

 

  1. 1. Lamp类的编写 
  2.  
  3.  
  4. package com.isoftstone.interview; 
  5.  
  6. /**
  7. * 每个Lamp元素代表一个方向上的灯,总共有12个方向,所有总共有12个Lamp元素。
  8. * 有如下一些方向上的灯,每两个形成一组,一组灯同时变绿或变红,所以,
  9. * 程序代码只需要控制每组灯中的一个灯即可:
  10. * s2n,n2s   
  11. * s2w,n2e
  12. * e2w,w2e
  13. * e2s,w2n
  14. * s2e,n2w
  15. * e2n,w2s
  16. * 上面最后两行的灯是虚拟的,由于从南向东和从西向北、以及它们的对应方向不受红绿灯的控制,所以,可以假想它们总是绿灯。
  17. */ 
  18. public enum Lamp { 
  19.      
  20.     /*每个枚举元素各表示一个方向的控制灯*/ 
  21.     S2N("N2S","S2W",false),S2W("E2N","E2W",false),E2W("W2E","E2S",false),E2S("W2N","S2N",false), 
  22.      
  23.     /*下面元素表示与上面的元素的相反方向的灯,它们的“相反方向灯”和“下一个灯”应忽略不计!*/ 
  24.     N2S(null,null,false),N2E(null,null,false),W2E(null,null,false),W2N(null,null,false), 
  25.       
  26.     /*由南向东和由西向北等右拐弯的灯不受红绿灯的控制;因为这四个方向都是右手方向,
  27.      * 在中国现实生活中车辆靠右行,所以右手边车辆不需要红绿灯控制可以随便行走车辆
  28.      * 不会与其他路线上的车辆冲突;所以,可以假想它们总是绿灯*/ 
  29.     S2E(null,null,true),N2W(null,null,true),W2S(null,null,true),E2N(null,null,true); 
  30.      
  31.     /*当前灯是否亮着,即是否为绿灯*/   
  32.     private boolean lighted; 
  33.     /*与当前灯同时为绿的对应方向*/    
  34.     private String opposite; 
  35.     /*当前灯变红时下一个变绿的灯*/    
  36.     private String next; 
  37.      
  38.     //带以上三个参数的构造方法 
  39.     private Lamp(String opposite, String next,boolean lighted) { 
  40.         this.opposite = opposite; 
  41.         this.next = next; 
  42.         this.lighted = lighted; 
  43.     } 
  44.      
  45.     /**
  46.      * 判断是否为绿灯的方法
  47.      * @return
  48.      */ 
  49.     public boolean isLighted(){ 
  50.         return lighted; 
  51.     } 
  52.      
  53.     /**
  54.      * 某个灯变绿时,它对应方向的灯也要变绿
  55.      */  
  56.     public void light(){ 
  57.         this.lighted = true
  58.         //如果opposite为null则使改方法死循环,就是一直亮着绿灯 
  59.         if(opposite != null){ 
  60.             /*valueOf()方法为枚举类自带的方法;把字符串名字传进去返回对应的枚举对象;
  61.              * 可能有的人会说为什么不直接把opposite变量定义成枚举Lamp型;
  62.              * 这里笔者这么考虑:如果定义成Lamp型,那么上面的S2N这些属性变量
  63.              * 里面不方便传值,改成现在这样写,即将opposite定义成String型的,
  64.              * 直接给这些属性变量传入一个字符串即可,方便了很多
  65.              */ 
  66.             Lamp.valueOf(opposite).light(); 
  67.         } 
  68.         System.out.println(name() + " lamp is green,下面总共应该有6个方向能看到汽车穿过!"); 
  69.     } 
  70.      
  71.     /**
  72.      * 某个灯变红时,对应方向的灯也要变红,并且下一个方向的灯要变绿
  73.      * @return 下一个要变绿的灯
  74.      */  
  75.     public Lamp blackOut(){ 
  76.         this.lighted = false
  77.         if(opposite != null){ 
  78.             Lamp.valueOf(opposite).blackOut(); 
  79.         } 
  80.         Lamp nextLamp = null
  81.         if(next != null){ 
  82.             nextLamp = Lamp.valueOf(next); 
  83.             //name()方法也是枚举类自带的方法,返回一个自身属性名 
  84.             System.out.println("绿灯从" + name() +"-------->切换为" + next); 
  85.             nextLamp.light(); 
  86.         } 
  87.         return nextLamp; 
  88.     } 
  89.  
  90.  
  91. 2. Road类的编写 
  92.  
  93. package com.isoftstone.interview; 
  94.  
  95. import java.util.ArrayList; 
  96. import java.util.List; 
  97. import java.util.Random; 
  98. import java.util.concurrent.ExecutorService; 
  99. import java.util.concurrent.Executors; 
  100. import java.util.concurrent.ScheduledExecutorService; 
  101. import java.util.concurrent.TimeUnit; 
  102.  
  103. /**
  104. * 每个Road对象代表一条路线,总共有12条路线,即系统中总共要产生12个Road实例对象。
  105. * 每条路线上随机增加新的车辆,增加到一个集合中保存。
  106. * 每条路线每隔一秒都会检查控制本路线的灯是否为绿,是则将本路线保存车的集合中的第一辆车移除,即表示车穿过了路口。
  107. */ 
  108. public class Road { 
  109.      
  110.     //vehicles代表车俩,是个车俩集合,包括大卡车、小驾车等等所有车俩 
  111.     List<String> vehicles = new ArrayList<String>(); 
  112.     //name成员变量表示方向 
  113.     String name = null
  114.      
  115.     public Road(String name){ 
  116.         this.name = name; 
  117.          
  118.         //模拟车辆不断随机上路的过程 
  119.         /*Executors是jdk5新特性中的执行器,可以这么记:我们起的工具类比如utils都是以s结尾,
  120.          * 改类如何用如何拼写必须记住,Executors类似,改类有大量的静态方法;改执行器可以new多种线程池,
  121.          * 当然也可以new出下面的单独线程,不管是线程池还是线程都返回一个ExecutorService类型的值
  122.          */ 
  123.         ExecutorService executor = Executors.newSingleThreadExecutor(); 
  124.         //Runnable是接口不能直接new出但是可以将其弄成内部类new出其的实现类 
  125.         executor.execute(new Runnable() { 
  126.              
  127.             @Override 
  128.             public void run() { 
  129.                 //产生999辆车 
  130.                 for(int i=1;i<1000;i++){ 
  131.                     try
  132.                         //休息1到10秒随机时间 
  133.                         Thread.sleep((new Random().nextInt(10) +1) *1000); 
  134.                     } catch (InterruptedException e) { 
  135.                         e.printStackTrace(); 
  136.                     } 
  137.                     /*内部类访问外部的成员变量可以讲外部类的改成员变量弄错final最终的,
  138.                     也可以在内部类中使用外部类名.this.外部类变量的方法达到目的*/ 
  139.                     vehicles.add(Road.this.name +"_" + i); 
  140.                 } 
  141.             } 
  142.         }); 
  143.          
  144.         //每隔一秒检查对应的灯是否为绿,是则放行一辆车 
  145.         //定时器(连环爆炸器)的编写,应用相当广泛,必会;new的是Scheduled(调度)调度池 
  146. ScheduledExecutorService timer = Executors.newScheduledThreadPool(1); 
  147.         timer.scheduleAtFixedRate(new Runnable() { 
  148.              
  149.             @Override 
  150.             public void run() { 
  151.                 //先检查路上有没有车辆 
  152.                 if(vehicles.size()>0){ 
  153.                     boolean lighted = Lamp.valueOf(Road.this.name).isLighted(); 
  154.                     if(lighted){ 
  155.                         //traversing:正在穿过 
  156.                         System.out.println(vehicles.remove(0) +" is traversing !"); 
  157.                     } 
  158.                 } 
  159.             } 
  160.         },   
  161.         1//过多少时间去干这件事 
  162.         1//隔多少时间再去干这件事 
  163.         TimeUnit.SECONDS);//说明上面数值的定量单位,是隔1秒呢还是1分钟或1小时呢; 
  164.     } 
  165.      
  166.  
  167.  
  168. 3. LampController类的编写 
  169.  
  170. package com.isoftstone.interview; 
  171.  
  172. import java.util.concurrent.Executors; 
  173. import java.util.concurrent.TimeUnit; 
  174.  
  175. /**
  176. * 车辆控制器,主要操作对象
  177. */ 
  178. public class LampController { 
  179.      
  180.     private Lamp currentLamp; 
  181.      
  182.     public LampController(){ 
  183.         //刚开始让由南向北的灯变绿; 
  184.         currentLamp = Lamp.S2N; 
  185.         currentLamp.light(); 
  186.          
  187.         /*每隔10秒将当前绿灯变为红灯,并让下一个方向的灯变绿*/ 
  188.         Executors.newScheduledThreadPool(1).scheduleAtFixedRate(new Runnable() { 
  189.              
  190.             @Override 
  191.             public void run() { 
  192.                 System.out.println("车辆有本事你来啊!"); 
  193.                 currentLamp = currentLamp.blackOut(); 
  194.             } 
  195.         },  
  196.         10,  
  197.         10
  198.         TimeUnit.SECONDS); 
  199.          
  200.     } 
  201.  
  202.  
  203. 4. MainClass类的编写 
  204.  
  205. package com.isoftstone.interview; 
  206.  
  207. public class MainClass { 
  208.  
  209.     /**
  210.      * @param args
  211.      */ 
  212.     public staticvoid main(String[] args) { 
  213.         /*产生12个方向的路线*/   
  214.         String[] directions = {"S2N","S2W","E2W","E2S","N2S","N2E","W2E","W2N","S2E","E2N","N2W","W2S"}; 
  215.          
  216.         for(int i=0;i<directions.length;i++){ 
  217.             new Road(directions[i]); 
  218.         } 
  219.  
  220.         /*产生整个交通灯系统*/ 
  221.         new LampController(); 
  222.     } 
  223.  

 

 

==================================================================================================

  作者:欧阳鹏  欢迎转载,与人分享是进步的源泉!

  转载请保留原文地址http://blog.csdn.net/ouyang_peng

==================================================================================================

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
高级开发必须理解的Java中SPI机制
高级开发必须理解的Java中SPI机制
12 0
六年Java开发,分享年薪50W+架构师一路成长的辛酸
13年下半年接触java,奇遇一般参加了java培训,期间甘苦自知。14年初如愿找到人生第一份工作,工资3k;对于之前的付出也算是回报吧 ,对于当时的我已经很满足了。 但是后来没想到公司是个坑, 入司半年有余,写的代码屈指可数;但是却结交了一位良师益友对我以后的职业发展和技术上提供了明灯,给予了不少帮助。所以说(塞翁失马,焉知非福)还是有些道理的。
22 0
阿里大牛都在读的10本Java实战书籍,Java开发进阶必备书单
关乎于程序员,除了做项目来提高自身的技术,还有一种提升自己的专业技能就是:多!看!书! 毕竟,书是学习的海洋呢!So,Java程序员你们准备好了吗?双手奉上Java程序员必读之热门书单。
21 0
3分钟教你用java开发一个小程序后台服务器~看完你也会
3分钟教你用java开发一个小程序后台服务器~看完你也会
19 0
一日一技:在Python开发中,如何让Java程序员抓狂
一日一技:在Python开发中,如何让Java程序员抓狂
11 0
【一名资深Java开发的经验浅谈】
【一名资深Java开发的经验浅谈】
22 0
手把手一步一步教你使用Java开发一个大型街机动作闯关类游戏21之enemy行走和死亡动画效果
手把手一步一步教你使用Java开发一个大型街机动作闯关类游戏21之enemy行走和死亡动画效果
42 0
手把手一步一步教你使用Java开发一个大型街机动作闯关类游戏20之enemy被攻击显示后退动画(block效果)
手把手一步一步教你使用Java开发一个大型街机动作闯关类游戏20之enemy被攻击显示后退动画(block效果)
33 0
手把手一步一步教你使用Java开发一个大型街机动作闯关类游戏19敌人可以被打死
手把手一步一步教你使用Java开发一个大型街机动作闯关类游戏19敌人可以被打死
28 0
手把手一步一步教你使用Java开发一个大型街机动作闯关类游戏18玩家攻击动画实现
手把手一步一步教你使用Java开发一个大型街机动作闯关类游戏18玩家攻击动画实现
28 0
+关注
字节卷动
You will never know how excellent you are unless you impel yourself once.
文章
问答
视频
文章排行榜
最热
最新
相关电子书
更多
JAVA开发手册1.5.0
立即下载
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载
相关实验场景
更多