黑马程序员--7k面试题交通灯

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


博客两次申请都没有通过,想死的心都有了,没办法,只能还是再写了,不过java的高新技术篇
我已经写过了,只是在发表的时候题目标注了javaSE,可能因为老师工作太辛苦了,有点疲劳了,但两个
7k的面试题确实没涉及,还好之前是看过的,现在只要理顺一下思路,分析下设计的思路还有代码的实现,
还是很简单的。

一、需求分析:

1.异步随机生成按照各个路线行驶的车辆。
2.交通灯只考虑红灯和绿灯,不考虑黄灯
3.只考虑左转车辆的控制信号灯,右转车辆不受信号灯控制
4.每辆车通过路口时间为10s
5.随机生成车辆时间间隔以及红绿灯交换时间间隔自定

二、画图分析:

张老师说画图是最直接分析系统的需求的,这里,我也照葫芦画了一个,嘿嘿
模拟交通图:

交通灯系统:

上图将复杂的交通逻辑转化为只需要考虑四条路线的交通逻辑;简化了模型的构造
我们需要将模型转化为面向对象的类
面向对象设计把握一个重要的经验:谁拥有数据,谁就对外提供操作这些数据的方法。
下面进行分析:
我们所分析的目标是整个交通系统,里面所包含的实体有车、交通灯,交通路
对车而言:由于我们不需要描述车自身的性质,比如说,对车轮记录其单位时间里所转动的次数。所以,我们可以把车用一串字符串表示
交通灯:其本身含有红绿灯的转换,以及控制每条路线所对应的同步路线和下一条路线,故我们把交通灯作为一个对象,其含有操作交通灯的方法和属性
路:路上包含许多车,故我们需要将其在内部定义一个集合,并定义相应的方法操作车,故我们将其定义为一个类
以上定义了所用到的类,但是,对于交通灯而言,我们还需要一个专门控制交通灯的转换的类。


三、类的代码实现:
1、交通灯:由于该模型涉及到12条路线的交通灯操作,如果将其设计为类,将变得比较复杂。枚举是一种特殊的类,它可以包含多个其本身的对象,
他为我们在这方面提供了方便,故想到用枚举。
package com.itheima.traffic;

public enum Lamp {
	/*每个枚举元素各表示一个方向的控制灯*/	
	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 String opposite;
	//下一个要变换的灯
	private String next;
	//灯的红绿
	private boolean lighted;
	
	public String getOpposite() {
		return opposite;
	}

	public String getNext() {
		return next;
	}

	public boolean isLighted() {
		return lighted;
	}

	//枚举类的构造方法私有化
	private Lamp(String opposite,String next,boolean lighted){
		this.opposite = opposite;
		this.next = next;
		this.lighted = lighted;
	}
	
	//当某个灯变亮时他相反方向的等也要变亮
	public void light(){
		//点亮灯
		this.lighted = true;
		//如果灯的相反方向的值不为空,就点亮
		if(opposite!=null){
			Lamp.valueOf(opposite).light();
		}
		//name 方法得到枚举对象的名字
		System.out.println(name() + " lamp is green,下面总共应该有6个方向能看到汽车穿过!");
	}
	
	//当某个灯变黒时(即为红灯时)对应相反方向的灯也要是红灯,且下一个灯要点亮
	public Lamp blackOut(){
		this.lighted = false;
		if(opposite!=null){
			Lamp.valueOf(opposite).blackOut();
		}
		
		Lamp nextLamp= null;
		if(next != null){
			nextLamp = Lamp.valueOf(next);
			System.out.println("绿灯从" + name() + "-------->切换为" + next);			
			nextLamp.light();
		}
		return nextLamp;
	}
}

2、路:对应这个模型,主要用于操作车辆,对应每一天路线,我们都会进该路线上的车辆进行增删操作,
即如果该路线是绿灯,则位于该路线最开始的车辆将通过。通过这个行为用删除集合中第一个元素表示。由于在该路线的尾部将会不断的增加车辆,
为了更贴近生活,车辆的增加时间间隔用以随机数表示。同时,我们每创建一条路线时,就需要启动在车辆增加和删除功能,故用到多线程。
package com.itheima.traffic;

import java.beans.VetoableChangeSupport;
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;

/**
 * 每个Road对象代表一条路线,总共有12条路线,即系统中总共要产生12个Road实例对象。
 * 每条路线上随机增加新的车辆,增加到一个集合中保存。
 * 每条路线每隔一秒都会检查控制本路线的灯是否为绿,是则将本路线保存车的集合中的第一辆车移除,即表示车穿过了路口。
 * 
 *
 */

public class Road {
	
	//车辆用集合字符串表示
	private List<String> vechiles = new ArrayList<String>();
	//每条路都有一个名字
	private String name = null;
	
	//声明构造方法
	public Road(String name){
		this.name = name;
		
		//启动一个线程模拟车辆上路的过程,即每隔一段时间向vechile集合中添加一两车
		ExecutorService pool = Executors.newSingleThreadExecutor();
		pool.execute(new Runnable(){
			@Override
			public void run() {
				for(int i=0;i<1000;i++){
					//睡眠1-10秒
					try {
						Thread.sleep((new Random().nextInt(10)+1)*1000);
						vechiles.add(Road.this.name+"--"+i);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				
			}
			
		});
		
		//设计定时器,每隔一秒就检查路上的等是否为绿灯,如果是就放行一辆车
		ScheduledExecutorService timer = Executors.newScheduledThreadPool(1);
		timer.scheduleAtFixedRate(
				new Runnable(){

					@Override
					public void run() {
						//首先检查路上是否有车
						if(vechiles.size()>0){
							boolean lighted = Lamp.valueOf(Road.this.name).isLighted();
							if(lighted){
								System.out.println(vechiles.remove(0)+" is traversing");
							}
							
						}
						
					}
					
				},
				1,
				1,
				TimeUnit.SECONDS
			);
		
	}
}

3.交通控制类,对交通灯进行控制并启动整个流程 :
package com.itheima.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();
		
		//定义一个定时器每个10秒钟就将当前灯变为不亮,并记录下一次要变换的灯
		ScheduledExecutorService timer = Executors.newScheduledThreadPool(1);
		timer.scheduleAtFixedRate(
				new Runnable() {
					@Override
					public void run() {
						System.out.println("hello");
						currentLamp = currentLamp.blackOut();
					}
				},
				10,
				10, 
				TimeUnit.SECONDS
			);
	}
}

4.运行整个系统的主类

package com.itheima.traffic;

public class MainClass {
	public static void main(String[] args) {
		/*产生12个方向的路线*/		
		String [] directions = new String[]{
				"S2N","S2W","E2W","E2S","N2S","N2E","W2E","W2N","S2E","E2N","N2W","W2S"		
		};
		for(int i=0;i<directions.length;i++){
			new Road(directions[i]);
		}
		
		new LampController();
	}
}

总结思考: 
对设计某一个系统,我们首先要根据其业务需求及描述归纳出其概念模型,将该模型进行分析,归纳,总结出其规律,画出其简要模型。
在根据整个模型进行面向对象的分析,确定出我们所需要的各个类,在这一步我们可以根据面向对象设计把握一个重要的经验:谁拥有数据,
谁就对外提供操作这些数据的方法。利用这个原则对其进行设计。最后写出我们所需的系统,然后进行相应的测试和代码优化。


ps:这一次理解整个系统的分析,设计再到代码的实现感觉轻松了好多,尤其是上面提到的张老师的那句对于面向对象的设计思想:
谁拥有数据,谁就对外提供操作这些数据的方法。简直是太清楚明了了!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值