--------------------- android培训、java培训、java学习型技术博客、期待与您交流! ----------------------
遇到问题不要偷懒,画图有助于理解问题
车辆的行驶顺序,先是直线,比如南向北,然后是左拐外南向西,其他三个方向类似
除去不受控制的灯,这样只剩下8条需要考虑,而这8条中都是成对出现的,所以只需要考虑四条就可以
右拐弯也有灯。只不过是常绿的
绿灯情况下,先是直行,后是拐弯,然后换灯
面向对象:
首先考虑这个情景有哪些对象
灯,灯的控制系统,汽车,路线
路线和灯绑定。汽车看到自己路上所对应的的灯绿了才会走,还要看前面是否有车,也就是说只有自己是第一个位置才能行走,于是路应该有add和remove方法用于增删车辆
路上的车可以看做是一个集合,于是路就应该有增加车辆和减少车辆的方法
面向对象设计的重要经验:谁拥有数据,谁就对外提供操作这些数据的方法,谁就是类
面向对象的分析涉及:人在黑板上画圆 人黑板园
关于灯的设计
无论何时都是12个灯,因此用到枚举
当一个灯变绿,相反方向的灯也会变绿,当一个灯变红,相反方向的灯也变红,而下一个等要变红或变绿,所以该枚举至少俩参数,对面的灯和下一个灯,还有一个参数是自己的状态,自己是不是绿的
灯变红和变绿方法应该返回下一个灯
首先创建一个类road,不同的路线有不同的名字,因此提供含参构造方法,构造方法里面不能sleep,否则永远不返回
publicclass Road {
//定义一个集合用来存储车辆
private List<String> list = new ArrayList<String>();
//路线的名字
private String name = null;
public Road(String name)
{
this.name = name;
//假设每1S路上上来一辆车,其他的不管
//车应该一辆辆上来,而不是一下子全部上来,因此要用计数器
//创建一个使用单个 worker 线程的 Executor 线程池
ExecutorService pool = Executors.newSingleThreadExecutor();
//如果有一个任务,交给一个线程池,线程池自己挑一个空闲的线程去执行他
pool.execute(new Runnable()//{}表示new了一个runnable的实现类对象
{
@Override
publicvoid run() {
for(int i = 0 ; i < 100 ; i++)
{
try {
//随机1-10秒钟上来一辆车
Thread.sleep((new Random().nextInt(10)+1)*1000);
//访问外部类成员变量本来可以直接访问,但如果外部类的变量名字和内部类的相同则需要外部类.this.属性名
} catch (InterruptedException e) {
e.printStackTrace();
}
list.add(Road.this.name+":"+i);
}
}
});
//创建一个调度池
ScheduledExecutorService timer = Executors.newScheduledThreadPool(1);
//计时器每个多长时间去干这件事。参数为要执行的代码,多少秒之后去做,每隔多少秒去做,计时单位
//重载形式是多少秒之后去做,只做一次
//timer.schedule(command, delay, unit)
timer.scheduleAtFixedRate(new Runnable(){
@Override
publicvoid run() {
//检查有没有车
if(list.size() > 0)
{
//假如灯是绿的
if(Lamp.valueOf(Road.this.name).isGreen())
{
//remove方法返回值是被移除的元素
System.out.println(list.remove(0)+"is removed!");
}
}
}},
1,
1,
TimeUnit.SECONDS);
}
}
创建灯.java
publicenum Lamp {
//S2N,S2W,E2W,E2S,N2S,N2E,W2E,W2N,S2E,E2N,N2W,W2S
//不使用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);
//点亮灯
privatebooleangreen;
//对应的灯的名字,为了解决先定义后使用的问题直接使用对象无法继续写
private String opposite;
//下一个灯
private String next;
//枚举的构造方法必须私有
private Lamp(String opposite,String next,boolean green)
{
this.opposite = opposite;
this.next = next;
this.green = green;
}
private Lamp()
{
}
//是否是亮的
publicboolean isGreen()
{
returngreen;
}
publicvoid becomegreen()
{
//opposite.becomegreen(); 我的灯亮了,就让对应的灯也亮,但是不能这样写,会陷入死循环
this.green = true;
//假如我为主,我有对应的灯,而对面的灯没有对应的灯
if(opposite != null)
{
Lamp.valueOf(opposite).becomegreen();
}
System.out.println(name()+"变绿了");
}
public Lamp becomered()
{
this.green = false;
if(opposite != null)
{
Lamp.valueOf(opposite).becomered();
}
Lamp nextLamp = null;
if(next != null)
{
nextLamp = Lamp.valueOf(next);
nextLamp.becomegreen();
}
System.out.println(name()+"变红了");
return nextLamp;
}
}
灯的控制器
publicclass LampControler {
private Lamp currentLamp;
public LampControler(){
//加定第一个灯为E2N,然后让他变绿灯
currentLamp = Lamp.S2N;
currentLamp.becomegreen();
ScheduledExecutorService c = Executors.newScheduledThreadPool(1);
c.scheduleAtFixedRate(new Runnable(){
@Override
publicvoid run() {
System.out.println("来啊");
//因为该方法需要下一个灯作为返回值使灯来回切换所以becomered方法需要返回下一个灯
currentLamp = currentLamp.becomered();
}
},
10,
10,
TimeUnit.SECONDS);
}
}主类
publicclass Main {
/**
* @param args
*/
publicstaticvoid main(String[] args) {
String[] str = new String[]{"S2N","S2W","E2W","E2S","N2S","N2E","W2E","W2N","S2E","E2N","N2W","W2S"};
for(String s : str)
{
new Road(s);
}
new LampControler();
}
}