黑马程序员_7K月薪面试题交通灯管理系统

时间:2023-02-17 21:11:22


-----Java培训、Android培训、iOS培训、.Net培训、期待与您交流!-----


今天花一上午学习了张老师关于交通灯管理系统的视频,不得不说老师讲的是在是好,老师也是一般人,也是通过一步步来实现的,coding中也会遇到bug,老师不仅示范了整个项目从创建,到面向对象的思想:“谁有数据,谁就对外提供操作这届数据的方法。”。还有


原始需求:

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

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

例如:

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

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

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

       。。

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

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

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

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

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

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

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

首先对题目进行解读:

通过结合实际,知道在十字路口,每个方向的车可以有三种选择,如由南来的车可以向北,向东,向西走,如此便有12条路线。

再每个方向向右拐的车不受红绿灯影响,如此便只考虑8条路线。再当有车南来北网时,此时也有车北来难往;有车由南向西拐时,此时也有车由北向东拐,如此,只需要考虑4条路线。

现在定为:由南向北(S2N),由南向西(N2W),由东向西(E2W),由东向南(E2S)。


然后视频中从面向对象的角度选择了几个典型的对象:

1,Road(路)

2,Lamp(红绿灯)

3,LampController(灯控制器)

4,MainClass(测试类)


Road拥有创建车和移除车的方法,Lamp代表红绿灯,具有转换颜色的方法,灯控制器能循环控制各个方向上的灯的循环开关


1,Road类

package com.traffic;

import java.util.ArrayList;
import java.util.List;
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<String> vechicles=new ArrayList<String>();
	
	private String name;
	public Road(String name){
		this.name=name;
		 ExecutorService pool=Executors.newSingleThreadExecutor();
		 pool.execute(new Runnable(){
			 public void run(){
				 for(int i=1;i<1000;i++){
					 try {
						Thread.sleep(1000);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					 vechicles.add(Road.this.name+"::"+i);
					 
				 }
			 }
		 });
		 ScheduledExecutorService timer=Executors.newScheduledThreadPool(1);
		 timer.scheduleAtFixedRate(new Runnable(){

			@Override
			public void run() {
				// TODO Auto-generated method stub
				if(vechicles.size()>0){
					boolean lighted=Lamp.valueOf(Road.this.name).isLighted();
					if(lighted){
						System.out.println(vechicles.remove(0)+" is passed!");
					}
				}
			}
		 
		 },
		 1, 
		 1,
		  TimeUnit.SECONDS);
		
	}
}

在这个类中,再一次学习了 java.util.concurrent.Executors工具类,这个类是从1.5才开始有的,具有方法创建同步的单线程,或调度线程。以及内部类中引用外部类的成员变量 Road.this.name.


2,Lamp

Lamp是一个枚举类。因为总共有12条路线,这是确定的,当由南向北的限时用完后再开始走由南向西,接着走由东向西,再由东向南,在循环到开头由南向西。用枚举类可以很好的把路线连接起来,又不会在编程中产生意外的路线。

package com.traffic;

public enum Lamp {
	
	S2N("N2S","S2W",false),S2W("W2S","E2W",false),E2W("W2E","E2S",false),E2S("S2W","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 String next;
	private String oppo;
	private boolean lighted;
	
	private Lamp(String oppo,String next,boolean lighted){
		this.oppo=oppo;
		this.next=next;
		this.lighted=lighted;
	}
	
	
	public boolean isLighted(){
		return lighted;
	}
	public void light(){
		lighted=true;
		System.out.println(name()+" is green");
		Lamp.valueOf(oppo).lighted=true;
		
//		if(oppo!=null){
//			Lamp.valueOf(oppo).light();
//		}
	}
	public Lamp blackOut(){
		lighted=false;
		Lamp.valueOf(oppo).lighted=false;
		System.out.println(name()+" is blackOut and light "+next);
		Lamp nextLamp=Lamp.valueOf(next);
		nextLamp.light();
		return nextLamp;
	}
}

这里又熟悉了枚举类,枚举类使每个独立的类的对象之间产生了联系。


3,灯控制器

灯控制器的代码很少,主要是调用Executors.newScheduledThreadPool()来定时循环切换红绿灯。

package com.traffic;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class LampController {

	private Lamp currentLamp;
	
	public LampController(){
		currentLamp=Lamp.S2N;
		currentLamp.light();
		
	 ScheduledExecutorService timer=Executors.newScheduledThreadPool(1);
	 timer.scheduleAtFixedRate(new Runnable(){
		 public void run(){
			 currentLamp=currentLamp.blackOut();
		 }
	 }, 
	 10, 
	 10, 
	 TimeUnit.SECONDS);
	}
}


4,测试类

package com.traffic;


public class MainClass {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		String[] directions="S2N,S2W,E2W,E2S,N2S,N2E,W2E,W2N,S2E,E2N,N2W,W2S".split(",");
		for(int i=0;i<directions.length;i++){
			new Road(directions[i]);
		}
		new LampController();
	}
}
上面类尤其要注意定义方向时不能写反了,否者出现的错误都不能找到。


通过这个项目,首先学习了如何去面对它,当看到一份需求文档,首先要读通文档,明白关键,把最核心的内容提取出来,像本项目,只需要考虑4条线路就可以,然后保证其他对应的4条线路同步。再就是剩下的4条右拐线路,只需要在定义时加入null,使其和其他线路在构造器中是相同的,再就是使用了java.util.concurrent包。提供了计时器,省去了自己使用实现Runnable接口,自己实现synchronized来创建线程,这些容易出错的代码。

还有就是,把12条线路的”车“装到ArrayList中,这是一个很好的方法,因为可以直接通过操作下标来移除最前面的“车”,然后自动实现后面的车占据前面的位置。



-----Java培训、Android培训、iOS培训、.Net培训、期待与您交流!-----