黑马程序员________7k面试题之交通灯

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


需求

交通灯管理系统

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

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

例如:

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

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

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

。。。

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

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

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

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

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

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

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




         通过分析可以知道十字路口一共存在     每个路口3个方向 * 一共4个路口 = 12个方向。而其中每个路口中向右拐的车不受信号灯控制,而剩下的八个等又是两两对应,所以我们只需要完成四个灯的逻辑关系即可。





        看过题目想自己先小试牛刀一下再看视频,就先自己做了一个。实现界面如下



      

      每隔一秒会自动刷新控制台,显示每个方向当前信号灯状态以及此方向的路上滞留车辆。实现代码如下:



package com.itheima.trafficlamp;



import java.util.Arrays;

import java.util.Random;



public class trafficLampDemo {



/**

 * @param args

 */

public static void main(String[] args) {

// TODO Auto-generated method stub

Resource resource=Resource.getResource();

Arrays.fill(resource.lamps,0,resource.lamps.length,Lamp.RED);//初始化开始都为红灯

new Thread(new AmountAuto(resource)).start();

new Thread(new ShowU(resource)).start();

new Thread(new LampAuto(resource)).start();

new Thread(new TrafficAuto(resource)).start();

}



}



class Resource{//定义一个资源类,里面有各个路口的车辆数和各个路口的红绿灯状态,由于此类对象需要在程序中具有唯一性,所以采用单例模式

int[] population=new int[12];//数组每一个元素的值代表一个一个路口上堆积的车辆数量

Lamp []lamps=new Lamp[12];//数组每一个元素值为当前信号灯的状态

private  static Resource resource=null;

private Resource(){}

public static Resource getResource(){

if(resource==null){

synchronized(Resource.class){//双重判断,在安全性保障的前提下保证程序的运行效率

if(resource==null){

resource=new Resource();

return resource;

}

}

}

return resource;

}

}







enum Lamp{//定义信号灯为一个枚举

RED(){

public Lamp nextLamp(){//覆写类中抽象方法获取下一个灯为绿灯

return GREEN;

}

public String getName(){

return "红灯";

}

},GREEN(){

public Lamp nextLamp(){//覆盖类中抽象方法获取下一个灯为红灯

return RED;

}

public String getName(){

return "绿灯";

}

};

private Lamp(){}

int stayTime=2;//定义绿灯的时间

public abstract Lamp nextLamp();

public abstract String getName();

}











class AmountAuto implements Runnable//这是一个对资源中汽车数量进行操作的一个线程

{

Resource resource;

AmountAuto(Resource resource)//他需要将程序内公共的资源接收进程序

{

this.resource=resource;

}

public void run()

{

Random random=new Random();//创建一个随机源

while(true){

try {

Thread.sleep(400);//每隔400毫秒进行一次无限循环

} catch (InterruptedException e) {

e.printStackTrace();

}

int index=random.nextInt(12);//循环过程得到一个0-11的随机数

resource.population[index]+=1;//将这个随机数作为资源中amount数组的角标对该角标的元素进行+=1操作,即模拟了随机产生一个去随机方向的车

}

}

}







class LampAuto implements Runnable{//这是一个对资源中交通灯的状态进行操作的一个线程

Resource resource;

public LampAuto(Resource resource) {//他也需要将公共资源包接收进来

this.resource = resource;

}



public void run(){

resource.lamps[2]=Lamp.GREEN;//根据分析2,5,8,11方向均为右转,所以信号灯一直为绿灯,不参与信号灯变化循环

resource.lamps[5]=Lamp.GREEN;

resource.lamps[8]=Lamp.GREEN;

resource.lamps[11]=Lamp.GREEN;

while(true){

resource.lamps[0]=resource.lamps[0].nextLamp();

resource.lamps[6]=resource.lamps[6].nextLamp();

if(resource.lamps[4].equals(Lamp.GREEN))//这是上个循环结束4号信号灯应该为绿灯,做判断是因为初始值为红灯。

resource.lamps[4]=resource.lamps[4].nextLamp();

if(resource.lamps[10].equals(Lamp.GREEN))//信号灯x和x+6同理,以下不在赘述

resource.lamps[10]=resource.lamps[10].nextLamp();

try {

Thread.sleep(Lamp.GREEN.stayTime*1000);

} catch (Exception e) {

e.printStackTrace();

}

resource.lamps[0]=resource.lamps[0].nextLamp();//每隔两秒关闭上一个

resource.lamps[6]=resource.lamps[6].nextLamp();//并打开下一个

resource.lamps[1]=resource.lamps[1].nextLamp();

resource.lamps[7]=resource.lamps[7].nextLamp();

try {

Thread.sleep(Lamp.GREEN.stayTime*1000);

} catch (Exception e) {

e.printStackTrace();

}

resource.lamps[1]=resource.lamps[1].nextLamp();

resource.lamps[3]=resource.lamps[3].nextLamp();

resource.lamps[7]=resource.lamps[7].nextLamp();

resource.lamps[9]=resource.lamps[9].nextLamp();

try {

Thread.sleep(Lamp.GREEN.stayTime*1000);

} catch (Exception e) {

e.printStackTrace();

}

resource.lamps[3]=resource.lamps[3].nextLamp();//八秒是一个循环,4个线路各有两秒的绿灯时间

resource.lamps[4]=resource.lamps[4].nextLamp();

resource.lamps[9]=resource.lamps[9].nextLamp();

resource.lamps[10]=resource.lamps[10].nextLamp();

try {

Thread.sleep(Lamp.GREEN.stayTime*1000);

} catch (Exception e) {

e.printStackTrace();

}

}

}

}



class TrafficAuto implements Runnable{//这是是根据信号灯状态而改变车辆数量的一个线程

Resource resource;



public TrafficAuto(Resource resource) {//同样需要操作同一个资源

this.resource = resource;

}

public void run(){

while(true){

try {

Thread.sleep(1000);//每隔一秒进行一次无限循环,有则执行,模拟车辆需要一秒通过

} catch (Exception e) {

e.printStackTrace();

}

for(int x=0;x<resource.lamps.length;x++){//遍历信号灯数组

if(resource.lamps[x].equals(Lamp.GREEN)){//如果有绿灯

if(resource.population[x]!=0)//且该路上的车辆不能为零(零再减就成负数,不符显示)

resource.population[x]-=1;//数量减1

}

}

}

}

}









class ShowU implements Runnable//这是一个在控制台上显示我们当前状态的线程

{

public ShowU(Resource resource) {//显示的是公共资源

this.resource=resource;

}



Resource resource;

public void run()

{

while(true){

try {

Thread.sleep(1000);//每隔一秒刷新一次

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println(

resource.lamps[0].getName()+"\t\t"+resource.lamps[1].getName()+"\t\t"+resource.lamps[2].getName()+"\r\n"+

"南-->北"+resource.population[0]+"      \t"+"南-->西"+resource.population[1]+"      \t"+"南-->东"+resource.population[2]+"\r\n\r\n"+

resource.lamps[3].getName()+"\t\t"+resource.lamps[4].getName()+"\t\t"+resource.lamps[5].getName()+"\r\n"+

"东-->西"+resource.population[3]+"      \t"+"东-->南"+resource.population[4]+"      \t"+"东-->北"+resource.population[5]+"\r\n\r\n"+

resource.lamps[6].getName()+"\t\t"+resource.lamps[7].getName()+"\t\t"+resource.lamps[8].getName()+"\r\n"+

"北-->南"+resource.population[6]+"      \t"+"北-->东"+resource.population[7]+"      \t"+"北-->西"+resource.population[8]+"\r\n\r\n"+

resource.lamps[9].getName()+"\t\t"+resource.lamps[10].getName()+"\t\t"+resource.lamps[11].getName()+"\r\n"+

"西-->东"+resource.population[9]+"      \t"+"西-->北"+resource.population[10]+"      \t"+"西-->南"+resource.population[11]+"\r\n"+

"--------------------------------------------------------------"

);

//打印每一路上的信号灯状态和等待车辆

}

}

}








        之后又看了张孝祥老师的视频,感觉印象最深的就是张老师的面向对象的思想。也就是谁拥有数据,就把操作该数据的方法定义给谁。比如人在黑板上年画圆,画圆的方法用到了原点坐标,半径,这些数据是圆的,所以该方法应该定义给圆。

那么根据张老师的思路是将车作为路的数据,又每个路对象对自己路上的车进行随机自增。然后每隔一秒对该路方向上的信号灯进行检查,如果是绿,则自减。这在思想上和我在思路上如出一辙,只是实现方式不同。但是张老师在信号灯上的思想却充分体现了面向对象的编程思想。我的程序中信号灯的枚举只单单作为一个状态而体现,就如flag的true和false一样,操作该状态的方法定义在了信号灯控制器上。但是根据面向对象的思想,信号灯的状态是信号灯的数据,所以该方法应该定义下信号灯内。信号灯内应该有以下几种方法:1,改变自己的的状态,同时改变与自己对应那一个方向灯的状态。2,记住自己的状态,并可返回。3,记住自己下一个逻辑顺序的信号灯。然后就可以设计信号灯控制器了,这个类因为在程序中时唯一的,所以用单例模式,如同我自己写的程序中resource类一样,该类对象唯一作用就是开启一个线程,调用信号灯中的方法,定时改变各个方向上的信号灯。







以下是张老师的信号灯类和信号灯控制器类



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

}

}


package com.isoftstone.interview.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(){

public  void run(){

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

currentLamp = currentLamp.blackOut();

}

},

10,

10,

TimeUnit.SECONDS);

}

}





这是张老师的实现界面,感觉没有我直观呀吼吼!但是自己的设计思想上有一定的不成熟,继续努力






。。。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值