黑马程序员-交通灯管理系统

---------------------- ASP.Net+Android+IOS开发</a>、 .Net培训、期待与您交流! ----------------------


项目要求

交通灯管理系统

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

异步随机生成按照各个路线行驶的车辆
例如:
       由南向而来去往北向的车辆 ---- 直行车辆
       由西向而来去往南向的车辆 ---- 右转车辆
       由东向而来去往南向的车辆 ---- 左转车辆
       。。。

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

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

具体信号灯控制逻辑与现实生活中普通交通灯控制逻辑相同,不考虑特殊情况下的控制逻辑
注:南北向车辆与东西向车辆交替放行,同方向等待车辆应先放行直行车辆而后放行左转车辆

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

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

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


分析

面向对象的分析和设计,有哪些对象?
路线
车辆
灯(红绿黄)
控制灯切换的控制器,也是一个对象

路线共有12条,如图中箭头所示

没有必要把车辆设计成对象,因为只是捕捉车辆经过的过程,用一个字符串表示车辆就可以了

车辆看到自己所在路线对应绿灯就穿过马路吗?不是,还要看前面是否有车,该问哪个对象前面是否有车呢?该问路,因为路拥有汽车,所以汽车的增加减少方法都在路对象上

无论何时只有十二个灯,所以十二盏灯使用枚举表示。右拐弯的路线本来不受灯的控制,但是为了让程序采用统一的处理方式,故假设有四个右拐弯长绿灯

灯控制器控制车辆的放行顺序:1-2-3-4(如上图),往复循环


Road类

import java.util.*;
import java.util.concurrent.*;
/**
路拥有车辆,所以路负责产生车辆、减少车辆。即向集合中加入元素,车辆经过表示为从集合中移除元素
*/
 
class Road
{
    private String name;    //路的名称
 
    //存放车辆的集合
    List<String> vehicles = new ArrayList<String>();
 
    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)
                    {
                    }
 
                    vehicles.add(Road.this.name + "_" + i);
                }
            }
        });
 
        //开启一个计时器线程池,满足绿灯且有车的情况下,每一秒过一辆车
        ScheduledExecutorService pool2 = Executors.newScheduledThreadPool(1);
        pool2.scheduleAtFixedRate(
            new Runnable()
            {
                public void run()
                {
                    //满足是绿灯且有车的情况下才行驶车辆
                    if(Lamp.valueOf(Road.this.name).isGreenLighted())
                    {
                        if(vehicles.size() > 0)
                        {
                            String vehicle = vehicles.remove(0);
                            System.out.println("车辆 " + vehicle + "路过");
                        }
                    }
                }
            },
            1,
            1,
            TimeUnit.SECONDS);
    }
}

Lamp类

/**
假设一个方向一个灯,一个灯只有红绿两种状态(不考虑黄灯),总共12盏灯。其中右拐的4个方向假设各有一个常绿的灯
 
为什么把灯设计成枚举?
因为灯的数量是固定不变的
*/
 
enum Lamp
{
    /*
    定义12盏灯,为什么传入的是字符串而不是Lamp类型的灯?
        以S2N("N2S", "S2W", false)为例,如果直接传入Lamp类型的N2S,会报错误,因为此时还不存在N2S对象
    */
    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);
 
    //boolean类型表示灯的颜色,绿true,红false
    private boolean isGreen = false;
 
    //相对应的灯,如果没有则为null
    String opposite = null;
 
    //下一个灯,如果没有则为null
    String nextLamp = null;
 
    private Lamp(String opposite, String nextLamp, boolean isGreen)
    {
        this.opposite = opposite;
        this.nextLamp = nextLamp;
        this.isGreen = isGreen;
    }
 
    public boolean isGreenLighted()
    {
        return isGreen;
    }
 
    //灯变绿的方法,对应的灯也要变绿
    public void turnGreen()
    {
        this.isGreen = true;
 
        //name()是枚举中的方法,返回枚举对象名称
        System.out.println(name() + "变绿灯,下面总共应该有6个方向能看到汽车穿过");
 
        if(opposite != null)
        {
            Lamp.valueOf(opposite).turnGreen();
        }
    }
 
    //灯变红的方法,对应的灯也要变红,如果存在下一个灯,则下一个灯变绿,返回下一个灯
    public Lamp turnRed()
    {
        this.isGreen = false;
        System.out.println(name() + "变红灯,禁止通行");
 
        if(opposite != null)
        {
            Lamp.valueOf(opposite).turnRed();
        }
 
        /*为什么要新定义一个Lamp next?(我遇到了下面的问题)
            如果直接使用nextLamp,代码如下:
 
            if(nextLamp != null)
            {
                Lamp.valueOf(nextLamp).turnGreen();
            }
            return Lamp.valueOf(nextLamp);
 
            如果这里的nextLamp等于null,即return Lamp.valueOf(null);    //存在问题
        */
        Lamp next = null;
        if(nextLamp != null)
        {
            next = Lamp.valueOf(nextLamp);
            next.turnGreen();
        }
        return next;
    }
}

LampControl类

import java.util.concurrent.*;
/**
灯控制器,控制灯每隔10秒切换一次
*/
 
class LampControl
{
    private Lamp currentLamp;
 
    public LampControl()
    {
        //设置当前灯为S2N
        currentLamp = Lamp.S2N;
        //当前灯变绿
        currentLamp.turnGreen();
 
        //开启一个计时器线程池,每10秒把当前灯变红,并设置下一个灯为绿灯
        ScheduledExecutorService pool = Executors.newScheduledThreadPool(1);
        pool.scheduleAtFixedRate(
            new Runnable()
            {
                public void run()
                {
                    currentLamp = currentLamp.turnRed();
                }
            },
            10,
            10,
            TimeUnit.SECONDS);
    }
}

主程序

/**
产生12条路,开启灯控制器
*/
 
class TrafficLampTest
{
    public static void main(String[] args)
    {
        //12条路的名称
        String[] roadsName = {"S2N", "S2W", "E2W", "E2S", "N2S", "N2E", "W2E", "W2N", "S2E", "E2N", "N2W", "W2S"};
 
        //产生12条路
        for(int i = 0; i < roadsName.length; i++)
        {
            new Road(roadsName[i]);
        }
 
        //开启灯控制器
        new LampControl();
    }
}




---------------------- ASP.Net+Android+IOS开发</a>、 .Net培训、期待与您交流! ----------------------
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值