黑马程序员——交通灯学习日记

------- "http://www.itheima.com"android培训"http://www.itheima.com"java培训、期待与您交流! ----------


/*

交通灯管理系统

一,需求分析:
1,需求:
异步随机生成按照各个线路行驶的车辆:直行,左转,右转(默认绿灯);
信号灯只考虑红绿,不考虑黄灯
左转受信号灯控制,右转不受信号灯控制
南北车辆与东西车辆交替放行。同方向车辆先放行直行车辆在放行左转车辆
每辆车通过路口时间为1秒
随机生成车辆时间及红绿灯交换时间自定,可以设置;
2,设计思路:
用到的对象:灯,灯的控制系统,车,路;

车属于路,题中不需要体现出车是如何过马路的。所以完全可以将车设计为由路对象控制的一个字符串,将路定义为一个集合,车字符串表示


注意:面向对象设计的一个经验:谁拥有数据,谁就提供方法;
灯对象在十二个行车方向上各有一个,且永远只有这十二个,所以使用枚举类型;
每个灯都有下一个该亮的灯和与自己状态相同的灯两个属性,并需要一个将自己变暗的方法并返回下一个变亮的灯
灯控制系统应该新开辟一个线程并设定定时器在固定时间之后将现在这个灯变暗并接受下一个该亮的灯,循环往复;
路对象里面有一个车辆的集合,存储了添加进来的每一辆车
二,编码实现功能:
1,写Road对象:
定义一个存储当前路上汽车的集合;每条路都有自己的名字,以构造函数的形式传递进来;
2.新启动一个线程池,用作并发增加每一条路上的车,上限为1000辆
ExcutorService pool = Excutors.newSingleThreadExcutor();
pool.excute(new Runnable() {
public void run() {
具体实现代码
}
});
注意:匿名内部类访问外部类的成员变量需要写为 (外部类类名.this.变量名),访问的局部变量用final修饰。
3.定义一个定时器来检查当前的交通灯的情况
ScheduledExecutorService timer = Executors.newScheduledThreadpool(1);
timer.scheduleAtFixedRate(

new Runnable(){

代码实现},1,1,TimeUnit.SECONDS);

*/

package com.isoftstone.interview.traffic;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class Road {
//定义交通工具集合

private List vehicles=new ArrayList();
//初始化路的名字
private String nameString=null;
public Road(String name){
this.name=name;
//创建线程池
ExecutorService pool=Executors.newSingleThreadExecutor();

//创建实现类
pool.execute(new Runnable(){
public void run() {
for (int i = 1; i < 10000; i++) {
try {
Thread.sleep((new Random().nextInt(10)+1)*1000);//随机产生1-10秒的随机数
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//内部类调用外部类的成员变量
vehicles.add(Road.this.nameString+"_"+i);
}
}
});


//定义一个定时器
ScheduledExecutorService timer=Executors.newScheduledThreadPool(1);
  
timer.scheduleAtFixedRate(
new Runnable(){
public void run() {
if(vehicles.size()>0){
boolean lighted=Lamp.valueOf(Road.this.nameString).isLighted();
if (lighted) {
System.out.println(vehicles.remove(0)+"is traversing");
}
      
}
},
1,
1,
TimeUnit.SECONDS
);
   
  
}
}

/*2,写Lamp对象:
1,先将十二个灯分类,有四个灯分别代表了横向和纵向的直行与左拐的关键灯;
有四个灯代表了与上一组那四个灯分别相对应的,即状态统一的四个灯;
最后四个灯代表了向右拐的,不受控制的,即可以长期为绿地四个灯;
2,每一个灯应该有一个状态,表示自己是亮的还是灭的;而且有一个方法返回i自己的状态变量属性;
3,所以每个灯应该有点亮自己和熄灭自己的方法;
4,每个灯都有一个随时与自己的状态保持一致的灯,所以定义这个变量且在这个灯执行点亮或熄灭自己的方法时将这个对应的灯也点亮或者熄灭;
此处为了避免形成死循环,所以要设定主灯与对应灯的概念,即主灯有对应的灯,但这个对应灯自身没有对应灯;
一个灯的对应灯应该由构造函数传递进来;
而在构造函数传递对应灯时又会遇到对象先定义后使用的问题,所以解决办法是不传递灯对象,而是传递灯的名字进来,再通过方法得到对应灯对象
5,四个主灯每个灯都有自己的“下一个灯”,即当自己熄灭之后就轮到下一个灯点亮,下一个灯在熄灭之后轮到下一个灯的下一个灯点亮,如此循环,此变量也又构造函数传递进来
6,四个对应灯都不具有对应灯,也不具有下一个灯
7,四个常量灯都不具有对应灯,也不具有下一个灯,且灯状态永远是绿地

8,当编写好了灯对象之后就可以在路对象中确定每一条路对应的自己名字相同的灯了;当灯控制器转换了灯的状态之后路的定时器方法就能检查到这一变化并作出停止放车过路的动作

*/

//由于行车路线只有12条,用枚举来实现。

package com.isoftstone.interview.traffic;


public enum Lamp {
 //2代表to,E代表东 S代表南,N代表北,W代表西,

 //设置灯的变动,车的走向
 S2N("N2S","S2W",false),S2W("N2E","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),E2N(null,null,true),N2W(null,null,true),W2S(null,null,true);
 //有参构造方法
 private Lamp(String opposite,String next,boolean lighted) { //构造方法的三个参数分别为对应灯,下一个灯,灯的状态
 this.oppositeLamp=opposite;
 this.nextString=next;
 this.lighted=lighted;
 }
 //无参构造方法
 private Lamp () {
 }
 //灯的状态
 private boolean lighted;
 //对面的灯
 private String oppositeLamp;
 //下一个灯
 private String nextString;
 //get方法返回灯的状态
 public boolean isLighted() {
 return lighted;
 }
 //灯亮
 public void light() {
 this.lighted=true;
 if (oppositeLamp!=null) {
 Lamp.valueOf(oppositeLamp).light();//返回枚举对象
 }
 System.out.println(name()+"lamp is green .下面可以看到六个方向的汽车穿过");
 }
 //灯灭并返回下一个灯
 public Lamp blackOut() {
 this.lighted=false;
 if (oppositeLamp!=null) {
 Lamp.valueOf(oppositeLamp).blackOut();//返回枚举对象
 }
 Lamp nextLamp=null;
 if (nextString!=null) {
 nextLamp=Lamp.valueOf(nextString);
 System.out.println("绿灯从"+name()+"--->切换为"+nextString);
 nextLamp.light();
 }
 return nextLamp;
 }
}


/*3,写等控制LampController对象:
1,控制器应该确定一个当前亮着的主灯,从而开始循环控制;

2,控制器每过一段时间就会让当前的主灯熄灭并得到下一个主灯并点亮它,此功能需要构造一个定时器

*/

//交通灯控制

public class LampController {

private Lamp currentLamp;

public LampController(){

//LampController构造方法中要设定第一个为绿的灯,所以刚开始让由南向北的灯变绿;  

currentLamp = Lamp

 currentLamp.light();

  //每隔10秒将当前绿灯变为红灯,并让下一个方向的灯变绿     

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

ScheduledExecutorService timer =  Executors.newScheduledThreadPool(1);

  timer.scheduleAtFixedRate(

 new Runnable(){

 public  void run(){

System.out.println("车来了");

currentLamp = currentLamp.blackOut();

}

},

10,

10,

TimeUnit.SECONDS);

}

}

/*

4,写主方法时要考虑:
1.在main方法中需要new出12条路并传入他们各自的name属性,这个功能可以构建一个string数组来遍历完成;这样每条路上就开始来车

2.new一个控制器对象,这样交通灯就开始工作,主灯路上的车就开始过路口,程序开始循环;

*/

public class MainClass 

{

public static void main(String[] args)

{

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

String [] directions = new String[]

{

"S2N","S2W","E2W","E2S","N2S","N2E","W2E","W2N","S2E","E2N","N2W","W2S"         

};

for(int i=0;i

{

new Road(directions[i]);

}

//获得LampController对象并调用其start方法,产生整个交通灯系统        

new LampController();

}


------- "http://www.itheima.com"android培训"http://www.itheima.com"java培训、期}与您交流! ----------















       



你可能感兴趣的:(黑马程序员——交通灯学习日记)