昨天学习了交通灯系统,今天又从新看了一下。下个小总结吧。刚一看就懵了,发现原来用的知识怎么都没用上?这一个月来的努力白费了吗。里边不仅加了计时器,线程池,等等新的知识,都是以前没见过的,之后又中很大的失落感,只有又硬着头皮重新看,第二次看的当中,发现了很多小知识点,象匿名内部类了,内部变量访问外部局部变量的方法,等等,得到了温故而知新的效果,而且用上了张老师的关于枚举的一些新知识,交通灯的12条路线用枚举真的很简单。就像张老师说的那样,看到新知识不能害怕,不要觉得没学过,只要用过一次就学会了,以后碰到类似的问题就可以举一反三了。
学到的最重要的就是如何使用面向对象,里边很重要的一句就是谁拥有数据,谁就对外提供了针对这个数据进行操作的方法。或者这句话现在还不是很了解。但是随着我学习的深入,会慢慢的去了解的。
像这个例子中,第一步就是画图,弄懂路和灯之间的逻辑。画图也非常有助于理解和分析问题,然后分析这个题目中有几个对象?首先,车是怎么运行的?他是要受到路和灯的控制,车该往哪里走?谁最清楚?灯和路最清楚,灯给车提供了信号,我让你走你才能走,你的听我的,我说的算。路会告诉车下一步 你直走还是转弯等等。所以在这里灯和路都是对象,在考虑灯,他会自己变红变绿吗?不会,谁在控制?lampControllor 他告诉我什么时候亮什么时候红。所以整个项目中的3个对象就明确了。这就是面向对象的思想吧。
可能我的基础还比较薄弱,对这个项目理解的也不好,现在的了解也只是皮毛。其中的精髓还没有领悟到,等以后基础好点,我会再回来看这道非常经典的项目,不然也对不起张老师。。。
下边是我根据张老师的视频,跟着打的代码。注释很多,欢迎拍砖。
class Road{
List<String> vechicles = new ArrayList<String>();
private String name = null;
public Road(String name){
this.name=name;
//第一个name是成员变量,第二个name是传进来的name是成员函数的局部变量
//这里要用一个线程池。1.5以上,线程池是一上来就产生好多个线程,有任务交给他运行的时候,看哪个空闲就交给他们去运行。
//当前我只需要一个线程 那么在线程池上标1. 线程池是一组线程,可以建立一个线程池,让他交给某个线程去做,
//我不交给某个线程,我要交给这个线程池。让他去调用某个线程。
//ExecutorService也是个线程池,等同于pool
ExecutorService pool = Executors.newSingleThreadExecutor();//执行器,如果一个类用作工具 它里边的方法全是静态方法,这个类的名字往往以类打头。像utils
pool.execute(new Runnable(){//这相当于new了一个Runnable实现类的对象,接口是不能直接new的,但是加个大括号表示new的是他的实现类
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);//加上车的名字和第几辆车。
//内部类要访问外部类的局部变量,局部变量要加final
//访问外部类的成员变量本来可以直接用外部类成员变量的名字,但是如果这个变量与自己类中的变量名字打架了就必须不能省略Road.this.
}
}
});
//定义一个定时器
ScheduledExecutorService timer = Executors.newScheduledThreadPool(1);
timer.scheduleAtFixedRate(
new Runnable(){
public void run(){
if(vechicles.size()>0){
boolean lighted = Lamp.valueOf(Road.this.name).isLighted();
//这个路线的名字得到对应的灯,我这条路线由南到北 当然就得到由南到北的灯了 枚举很爽吧
if(lighted==true){
System.out.println(vechicles.remove(0)+"is traversing!");
//这里返回的是 被移走的那个东西。
}
}
}
},
1,//过多少秒之后去干这个事
1, //干完之后在过多少秒接着干?
TimeUnit.SECONDS);//这个是前面数字的计数单位
/*timer.schedule(
new Runnable(){},
delay,//delay就是过多长时间干conmand这件事
unit);*/
}
}
enum Lamp {
S2N("N2S","S2W",false),S2W("N2E","E2W",false),E2W("W2E","E2S",false),E2S("W2N","S2N",false),//只要控制住这四条线路就ok
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.opposite = 传过来的opposite
this.next = next;
}
private Lamp(){//这里要补一个无参构造方法,因为上边的元素有的没有参数,
//为了让他们不报错,才搞一个这个
}
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(); //这里是获得字符串opposite的对象.变绿
}//我有对应的灯的时候我才让对应的灯亮 比如我东亮了,东对应的西就亮了,
//这时西就没对应的灯了,不然就死循环了
System.out.println(name()+"Lamp is Green,下边应该有六个方向能看到汽车通过");
}
public Lamp blackOut(){//灯变红
this.lighted = false;
if(opposite != null){
Lamp.valueOf(opposite).blackOut();
}
Lamp nextLamp = Lamp.valueOf(next);
if(next != null){
System.out.println("绿灯从"+"-------》切换为"+next);
nextLamp.light();
}
return nextLamp;
}
}
class LampController {
private Lamp currentLamp;
public LampController(){
currentLamp = Lamp.S2N;
currentLamp.light();
ScheduledExecutorService timer = Executors.newScheduledThreadPool(1);
timer.scheduleAtFixedRate(
new Runnable(){
public void run(){
currentLamp = currentLamp.blackOut();//当前的灯变黑,我的当前灯应该指向新变绿的灯。
}
},
2,
2,
TimeUnit.SECONDS);
}
}
class MainClass {
/**
* @param args
*/
public static void main(String[] args) {
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();
}
}