------- android培训、java培训、期待与您交流! ----------
一、思想,是贯穿整个程序始末的灵魂。只会写程序,看程序,而不会思考的程序员是不成功的程序员。学以致用,生活当中的十字路口是没有class Object,没有枚举,更没有多线程。如何让在大马路上行驶的车辆到十字路口的时候听从那些颜色不同的红绿灯的指挥?如何控制红绿灯闪亮的次序?每个灯亮的时间?以及如何让在十字路口被等待的汽车按照现实需求顺利穿过十字路口?这些都涉及到了对现实的抽象思维过程,只有对这个过程的缜密、深度抽取,让这些跟程序挂上钩,这时大脑里才会渐渐溢出代码的迹象。
二、深度剖析交通灯的 管理系统
1) Road类:用名词提炼法,先分析此需求中的各个名词对象,首先,汽车到路口,看灯,是否通过,如果,把这些一系列的行为封装在汽车这个对象里,显然,汽车通过了十字路口,这个对象就不存在我们这个路口过程中了;应该用哪个对象来描述来往的车辆,并使每一个车辆都拥有这个行为:大马路--集合,集合中装着来往的车辆,路上行驶着过去的车辆(删除元素)与过来的车辆(添加元素),这样,自然就跟集合代码联系上了;由于车辆的到来是随机的,可以在路初始化时就给它放一些车辆,即在Road对象的构造方法中随机添加车。在路上随机添加车,涉及到线程的操作,虽然用我们之前成熟的多线程Thread也可以实现,但是,在JDK1.5版本后,出现了线程的工具类Executors,这个工具类,我们可以用这个新工具类来实现,比较方便。用路线名_id表示车辆。
publicclass Road {
private List<String> vechicles = new ArrayList<String>();//集合中存储着来往的车辆
private String name =null; 表示方向的name属性
public Road(String name){
this.name= name;
ExecutorService pool = Executors.newSingleThreadExecutor();//创建一个使用单个worker 线程的 Executor,以无界队列方式来运行该线程
pool.execute(new Runnable(){
public void run(){
for(int i=1;i<1000;i++){
try {
Thread.sleep((new Random().nextInt(10) +1) * 1000);//每隔从1-10之间的随机秒数就添加一辆车
}catch(InterruptedException e) {
e.printStackTrace();
}
vechicles.add(Road.this.name + "_" + i);
}
}
});
//定时检查是否为绿灯,是的话,就从路的车辆集合中减少一辆车。可以用来创建定时任务。
ScheduledExecutorService timer= Executors.newScheduledThreadPool(1);//创建一个大小为1的线程池
timer.scheduleAtFixedRate(//以固定一秒的时间间隔来查看是否是绿灯
new Runnable(){
public void run(){
if(vechicles.size()>0){
boolean lighted = Lamp.valueOf(Road.this.name).isLighted();
if(lighted){
System.out.println(vechicles.remove(0) + " is traversing !");
}
}
}
},
1,
1,
TimeUnit.SECONDS);
三、 lamp类:我们只知道红,绿,黄三种颜色的灯,是否可将枚举元素定义成这三种类型呢?试想一下:如果由南向北的车与由南向西,还有由南右转弯的车同时过了十字路口后,他们三个的方向显然是不够的;由于在十字路口各个方向的车有各自不同的路线方向,需要受到不同的指示;可以将各个路线与要看的交通灯绑在一块,即,每一条路线都有自己的灯。为了使模块统一化,每个路线的右转弯虽然没有交通灯,在我们的程序中它也有一种交通灯,只不过这个方向的灯永远都是常绿状态,保证了与现实的一致性。按照不同的方向数一下,总共有12条不同的路线,所以,系统中总共要产生12个交通灯。每一个Lamp对象中的亮黑状态用逻辑值lighted变量表示,Lamp对象中还要有一个opposite变量来表示它们相反方向的灯,还需要用一个next变量来表示此灯变亮后的下一个变亮的灯。这三个变量可以用构造方法的形式进行初始化。每个交通灯都维护一个状态:亮(绿)或不亮(黑),每个交通灯要有变亮和变黑(不亮)的方法,并且能返回自己的亮黑状态。除了右拐弯方向的其他8条路线的灯,是两两成对的,可以分为4组,所以只需要从这4组中各取出一个灯,对这4个灯依次轮询变亮,与这4个灯方向对应的灯则随之一同变化,所以Lamp类中要有一个变量来记录它的相反方向的灯,在灯的状态变化的同时,与它相对应方向的灯也随之产生相同的变化;当前灯变黑,伴随着它的下一个灯要变亮。
publicenum 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,booleanlighted){
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;
}
}
四、交通灯控制系统LampController类的设计:此类的实现是负责控制各个方向的交通灯的显示,很容易想到,此类的实现是必须的,由于在整个系统中,只有一个核心的控制体系,所以这个控制体系是共享资源,为了避免冲突,需要把这个控制系统设计成单例。
public class LampController {
private Lamp currentLamp;//当前灯
public LampController(){
//刚开始让由南向北的灯变绿;
currentLamp = Lamp.S2N;//初始化第一个变绿的灯
currentLamp.light();
/*每隔10秒将当前绿灯变为红灯,并让下一个方向的灯变绿*/
//每间隔10秒就把当前灯的状态由绿灯变成红灯,并且让下一个方向的灯变成绿灯
ScheduledExecutorService timer= Executors.newScheduledThreadPool(1);
timer.scheduleAtFixedRate(
new Runnable(){
public void run(){
currentLamp = currentLamp.blackOut();
}
},
10,
10,
TimeUnit.SECONDS);
}
}
五、主程序MainClass类的设计
在程序启动时,需要初始化12个方向的路线,并且根据不同的路线名来初始化Road对象,初始化完成后,启动交通灯控制系统类,一个简单地交通灯控制系统就完成了。
MainClass类的关键代码如下:
public staticvoidmain(String[] args) {
初始化12个方向的路线
String[] directions = newString[]{
"S2N","S2W","E2W","E2S","N2S","N2E","W2E","W2N","S2E","E2N","N2W","W2S"
};//初始化12个方向的路线
for(int i=0;i<directions.length;i++){
new Road(directions[i]);//循环初始化Road对象,产生车辆
}
new LampController();//进入控制系统
}