黑马程序员 十七、面试题之交通灯管理系统—面向对象的分析与设计、Road 类、Lamp 类、LampController 类、MainClass类)

Java帮帮-IT资源分享网

 黑马程序员——面试题之交通灯管理系统

Road 类、Lamp 类、LampController 类、MainClass类
  

需求:

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

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

例如:

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

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

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

。。。

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

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

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

逻辑。

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

辆。

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

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

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

1、面向对象的分析与设计

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

少一辆车。

设计一个 Road 类来表示路线,每个 Road 对象代表一条路线,总共有 12 条路线,即系

统中总共要产生 12 个 Road 实例对象。

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

每条路线每隔一秒都会检查控制本路线的灯是否为绿,是则将本路线保存车的集合中

的第一辆车移除,即表示车穿过了路口。

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

一个方向的灯变绿。

2、设计一个 Lamp 类来表示一个交通灯,每个交通灯都维护一个状态:亮(绿)或不

亮(红),每个交通灯要有变亮和变黑的方法,并且能返回自己的亮黑状态。

总共有 12 条路线,所以,系统中总共要产生 12 个交通灯。右拐弯的路线本来不受灯的

控制,但是为了让程序采用统一的处理方式,故假设出有四个右拐弯的灯,只是这些灯为常

亮状态,即永远不变黑。

3、除了右拐弯方向的其他 8 条路线的灯,它们是两两成对的,可以归为 4 组,所以,

在编程处理时,只要从这 4 组中各取出一个灯,对这 4 个灯依次轮询变亮,与这 4 个灯方向

对应的灯则随之一同变化,因此 Lamp 类中要有一个变量来记住自己相反方向的灯,在一个

Lamp 对象的变亮和变黑方法中,将对应方向的灯也变亮和变黑。每个灯变黑时,都伴随者

下一个灯的变亮,Lamp 类中还用一个变量来记住自己的下一个灯。

4、无论在程序的什么地方去获得某个方向的灯时,每次获得的都是同一个实例对象,

所以 Lamp 类改用枚举来做显然具有很大的方便性,永远都只有代表 12 个方向的灯的实例

对象。

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

2、Road 类的编写

每个 Road 对象都有一个 name 成员变量来代表方向,有一个 vehicles 成员变量来代表方

向上的车辆集合。

在 Road 对象的构造方法中启动一个线程每隔一个随机的时间向 vehicles 集合中增加一

辆车(用一个“路线名_id”形式的字符串进行表示)。

在 Road 对象的构造方法中启动一个定时器,每隔一秒检查该方向上的灯是否为绿,是

则打印车辆集合和将集合中的第一辆车移除掉

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实例对

象。

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

* 每条路线每隔一秒都会检查控制本路线的灯是否为绿,是则将本路线保存车的集合中的

第一辆车移除,即表示车穿过了路口。

* @author 张孝祥 www.it315.org

*

*/

public class Road {

private List<String> vechicles = new ArrayList<String>();

private String name =null;

/*在这个构造函数中,传回哪个方向的车,

先开启一个线程池用于产生车辆,一个定时器用于观察交通灯状态*/

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((new Random().nextInt(10) + 1) *

1000);

} catch (InterruptedException e) {

e.printStackTrace();

}

vechicles.add(Road.this.name + "_" + i);

}

}

});

//每隔一秒检查对应的灯是否为绿,是则放行一辆车

//产生一个单线程,创建定时器

ScheduledExecutorService timer =

Executors.newScheduledThreadPool(1);

timer.scheduleAtFixedRate(

new Runnable(){

public void run(){

//判断路上是否有车,有则进行相应的操作

if(vechicles.size()>0){

boolean lighted =

Lamp.valueOf(Road.this.name).isLighted();

//每隔1秒让车通行,通行前要先判断灯是否亮,亮了才能通行,即从集合中移除

if(lighted){

System.out.println(vechicles.remove(0)

+ " is traversing !");

}

}

}

},

1,

1,

TimeUnit.SECONDS);

}

}
 

3、Lamp 类的编写

系统中有 12 个方向上的灯,在程序的其他地方要根据灯的名称就可以获得对应的灯的

实例对象,综合这些因素,将 Lamp 类用 java5 中的枚举形式定义更为简单。

1、每个 Lamp 对象中的亮黑状态用 lighted 变量表示,选用 S2N、S2W、E2W、E2N

这四个方向上的 Lamp 对象依次轮询变亮,Lamp 对象中还要有一个 oppositeLampName 变量

来表示它们相反方向的灯,再用一个 nextLampName 变量来表示此灯变亮后的下一个变亮的

灯。这三个变量用构造方法的形式进行赋值,因为枚举元素必须在定义之后引用,所以无法

再构造方法中彼此相互引用,所以,相反方向和下一个方向的灯用字符串形式表示。

2、增加让 Lamp 变亮和变黑的方法:light 和 blackOut,对于 S2N、S2W、E2W、E2N

这四个方向上的 Lamp 对象,这两个方法内部要让相反方向的灯随之变亮和变黑,blackOut

方法还要让下一个灯变亮。

3、除了 S2N、S2W、E2W、E2N 这四个方向上的 Lamp 对象之外,其他方向上的 Lamp

对象的 nextLampName 和 oppositeLampName 属性设置为 null 即可,并且 S2N、S2W、E2W、

E2N 这四个方向上的 Lamp 对象的 nextLampName 和 oppositeLampName 属性必须设置为

null,以便防止 light 和 blackOut 进入死循环。

代码:

/**

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

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

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

* s2n,n2s

* s2w,n2e

* e2w,w2e

* e2s,w2n

* s2e,n2w

* e2n,w2s

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

灯的控制,

* 所以,可以假想它们总是绿灯。

* @author 张孝祥 www.it315.org

*

*/

/**/

public enum Lamp {

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

S2N("N2S","S2W",false),S2W("N2E","E2W",false),E2W("W2E","E2S",fal

se),E2S("W2N","S2N",false),

/*下面元素表示与上面的元素的相反方向的灯,它们的“相反方向灯”和“下一个灯”应

忽略不计!*/

N2S(null,null,false),N2E(null,null,false),W2E(null,null,false),W2

N(null,null,false),

/*由南向东和由西向北等右拐弯的灯不受红绿灯的控制,所以,可以假想它们总是绿

灯*/

S2E(null,null,true),E2N(null,null,true),N2W(null,null,true),W2S(n

ull,null,true);

private Lamp(String opposite,String next,boolean lighted){

this.opposite = opposite;

this.next = next;

this.lighted = lighted;

}

/*当前灯是否为绿*/

private boolean lighted;

/*与当前灯同时为绿的对应方向*/

private String opposite;

/*当前灯变红时下一个变绿的灯*/

private String next;

//灯的判断是否亮的方法

public boolean isLighted(){

return lighted;

}

/**让这个方向的等亮起来

* 某个灯变绿时,它对应方向的灯也要变绿

*/

public void light(){

this.lighted = true;

if(opposite != null){

Lamp.valueOf(opposite).light();

}

System.out.println(name() + " lamp is green,下面总共应该有6个

方向能看到汽车穿过!");

}

/**

* 某个灯变红时,对应方向的灯也要变红,并且下一个方向的灯要变绿

* @return 下一个要变绿的灯

*/

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;

}

}
 

4、LampController 类的编写

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(){

public void run(){

System.out.println("来啊");

currentLamp = currentLamp.blackOut();

}

},

10,

10,

TimeUnit.SECONDS);

}
 

5、MainClass 类的编写

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

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

public class MainClass {

/**

* @param args

*/

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();

}

}

打印结果:/*N2S lamp is green-----有六个方向的车经过

S2N lamp is green-----有六个方向的车经过

N2S_1 is traversing !

S2N_1 is traversing !

N2W_1 is traversing !

S2N_2 is traversing !

E2N_1 is traversing !

S2E_1 is traversing !

S2N_3 is traversing !

N2S_2 is traversing !

S2N_4 is traversing !

开始跑吧

绿灯从S2N-------->切换为S2W

N2E lamp is green-----有六个方向的车经过

S2W lamp is green-----有六个方向的车经过

W2S_1 is traversing !

S2E_2 is traversing !

N2W_2 is traversing !

S2W_1 is traversing !

W2S_2 is traversing !

N2E_1 is traversing !

N2E_2 is traversing !

N2E_3 is traversing !

S2W_2 is traversing !

W2S_3 is traversing !

E2N_2 is traversing !

S2E_3 is traversing !

E2N_3 is traversing !

S2E_4 is traversing !

开始跑吧

绿灯从S2W-------->切换为E2W

W2E lamp is green-----有六个方向的车经过

E2W lamp is green-----有六个方向的车经过

E2W_1 is traversing !

N2W_3 is traversing !

E2W_2 is traversing !

W2E_1 is traversing !

E2W_3 is traversing !

W2E_2 is traversing !

W2S_4 is traversing !

E2W_4 is traversing !

N2W_4 is traversing !

W2E_3 is traversing !

S2E_5 is traversing !

E2N_4 is traversing !

E2W_5 is traversing !

W2S_5 is traversing !

N2W_5 is traversing !

W2E_4 is traversing !

*/

Java帮帮-IT资源分享网

时间: 2024-08-02 18:55:56

黑马程序员 十七、面试题之交通灯管理系统—面向对象的分析与设计、Road 类、Lamp 类、LampController 类、MainClass类)的相关文章

网络资源-黑马程序员Java 知识——精华总结

获取更多资源Java帮帮IT资源分享网 一.黑马程序员-java 概述与基础知识.................................................................................6 1.何为编程?...................................................................................................................6 2.J

黑马程序员 十八、银行业务系统等

Java帮帮-IT资源分享网 NumberManager 类.NumberMachine 类.CustomerType 枚举类.ServiceWindow 类.MainClass 类与 Constants 类  黑马程序员--面试题之银行业务系统  1.需求 模拟实现银行业务调度系统逻辑,具体需求如下:  银行内有 6 个业务窗口,1 - 4 号窗口为普通窗口,5 号窗口为快速窗口,6 号窗口为 VIP 窗口.  有三种对应类型的客户:VIP 客户,普通客户,快速客户(办理如交水电费.电话费

黑马程序员 一、java 概述与基础知识

获取更多资源关注Java帮帮IT资源分享网 一.黑马程序员-java 概述与基础知识 1.何为编程? 编程就是让计算机为解决某个问题而使用某种程序设计语言编写程序代码,并最终得到结果 的过程. 为了使计算机能够理解人的意图,人类就必须要将需解决的问题的思路.方法.和手段通 过计算机能够理解的形式告诉计算机,使得计算机能够根据人的指令一步一步去工作,完 成某种特定的任务.这种人和计算机之间交流的过程就是编程.   2.Java 语言概述,历史.特点 是 SUN(Stanford Universit

黑马程序员 二、方法与数组

获得更多资源关注Java帮帮IT资源分享网  二.黑马程序员-方法与数组 第二篇: 1.什么是方法(Method)? 方法是一组为了实现特定功能的代码块的集合.方法在语法上的功能主要有以下两个: ①:结构化代码 将代码按照功能进行组织,使代码的结构比较清晰,容易阅读和修改,也就是程序的可维护 性强. ②:减少代码重复 一个固定的功能,可能会在程序中多次使用,在使用时只需要调用写好的方法,而不用重复 书写对应的功能代码. 方法在书写时需要注意以下两点: ①:逻辑严谨 方法实现的一个完整的功能,所以

黑马程序员 九、IO 操作(1)

Java帮帮-IT资源分享网  九.黑马程序员-IO 操作(1) 第九篇 IO 文件操作(1)  1.IO 的概述和 File 方法 IO 流用来处理设备之间的数据传输 Java 对数据的操作是通过流的方式 Java 用于操作流的对象都在 IO 包中 File 类在整个 IO 包中与文件本身有关的操作类,所有的与文件本身有关指的是创建.删除 文件等操作.在 java.io 包中的 File 类本身是一个跨平台的文件操作类,所以在操作中要更 多的考虑到各个操作系统的区别. File 即指文件也指文

黑马程序员 三、面向对象(1))

Java帮帮-IT资源分享网  三.黑马程序员-面向对象(1) 第三篇:  1.什么叫面向对象? 面向对象(Object-Oriented,简称 OO)就是一种常见的程序结构设计方法. 面向对象思想的基础是将相关的数据和方法放在一起,组合成一种新的复合数据类型,然后 使用新创建的复合数据类型作为项目的基础. 面向对象是一个很抽象的概念,它相对面向过程而言. 过程与对象都是一种解决问题的思想. 面向过程:强调的是功能行为,一种过程,先干啥,再干啥; 面向对象:将功能封装到对象里,强调的是具备某功能

黑马程序员 十一、网络编程

Java帮帮-IT资源分享网  十一.黑马程序员-网络编程 第 11 天:网络编程(1)  1.什么是网络编程? 网络编程的本质是两个设备之间的数据交换,当然,在计算机网络中,设备主要指计算 机.数据传递本身没有多大的难度,不就是把一个设备中的数据发送给两外一个设备,然后 接受另外一个设备反馈的数据.现在的网络编程基本上都是基于请求/响应方式的,也就是 一个设备发送请求数据给另外一个,然后接收另一个设备的反馈.在网络编程中,发起连接 程序,也就是发送第一次请求的程序,被称作客户端(Client)

黑马程序员 四、面向对象(2)

Java帮帮-IT资源分享网四.黑马程序员-面向对象(2) 第四篇:  1.基本数据类型的包装类 引言:Java 提倡的万物皆对象,但是数据类型的划分出现了基本数据类型和引用数据类型, 那么我们怎么能把基本数据类型称为对象呢?  除了 Integer 和 Character 定义的名称和对应的基本类型差异大,其他六种都是将首字母大写 就可以了. Integer,Byte,Float,Double,Short,Long 都是 Number 类的子类.(Number 类后面讲): Character

黑马程序员 七、集合框架(1)

Java帮帮-IT资源分享网  七.黑马程序员-集合框架(1)  第七篇 集合框架(1)  1.集合类 & 容器 为什么出现集合类? 面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,就要 对对象进行存储,集合就是存储对象最常用的一种方式. 数组和集合类同是容器,有何不同? 数组虽然也可以存储对象,但长度是固定的:集合长度是可变的.数组中可以存储任意 数据类型,集合只能存储对象. 集合类的特点 集合只用于存储对象,集合长度是可变的,集合可以存储不同类型的对象. 我的总结:集