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

来源:互联网 发布:手机ssh连接linux 编辑:程序博客网 时间:2024/06/07 03:02

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

一、 面向对象分析和设计

面向对象设计把握一个重要的经验:谁拥有数据,谁就对外提供操作这些数据的方法。

人在黑板上画圆:这个动作涉及到三个类,Person,blackboard,Circle画圆的方法draw()到底是哪个类中的方法呢?

画圆需要圆心坐标(x,y)和半径radius,这些数据在Circle类中上,所以Circle提供操作这些数据的方法draw();分析可得画圆的动作draw()是Circle提供的。

二、 用面向对象的方式设计如下情景:

1、两块石头磨成一把石刀,石刀可以砍树,树可以做成椅子。

Stone --> StoneKnife --> Tree -->Material --> Chair

//Stone不能自己提供一个方法把自己变成石刀,所以Stone需要被使用,需要工具:

StoneKnife =KnifeFactory.creatKnife(stone);

//StoneKnife自己有一个方法把Tree变成Material木材

Material = StoneKnife.cut(tree);

//Tree不能把自己变成一把Chair椅子,需要工具:

Chair = ChairFactory.makeChair(material)     

2、球从一根绳子的一端移动到另一端:

Ball ,Rope两个对象似乎没有太大关系,仔细分析发现Ball本质是为Ball的移动提供一个方向(路线)。

由此可知:

Rope对象需要有获取当前点的下一个点的方法nextPoint(),同时Rope要有两个成员变量:起始点(start)、结束点(end)。

Ball要有一个move()移动的方法,方法内部rope调用next()方法返回当前点的下一个点再赋给当前点currentPoint。

所以,Ball要绑定Rope,Ball在构造的时候需要接收一个Rope对象和小球的当前点currentPoint,

代码示例描述小球和绳子:

class Rope{private Point start;private Point end;public Rope(Point start,Point end){this.start = start;this.end = end;}public Point nextPoint(Point currentPoint){/* 通过两点一线的数学公式可以计算出当前点的下一个点,这个细节不是设计阶段要考虑的问题,如果当前点是终止点,则返回null,如果当前点不是线上的点,抛出异常。 */}}class Ball{private Rope rope;private Point currentPoint;public Ball(Rope rope,Point start){this.rope = rope;this.currentPoint = start;}public void move(){currentPoint = rope.next(currentPoint);System.out.println("小球移动到了"+currentPoint);}}

三、 交通灯管理系统分析和设计:

项目需求:模拟实现十字路口的交通灯系统

1、十字路口要有红绿灯,由现实可知每一个方向上右3个灯,一共12个灯---Lamp

2、如果我们只考虑红灯和绿灯,我们需要有一个红灯和绿灯切换的工具:红绿灯控制器--LampController

3、十字路口需要有路:Road,并且我们经分析知道,灯和路是绑定在一起的,有多少个方向的灯,就需要有多少个方向的路---Road

详细分析:

Lamp枚举的创建:

(我们把亮代表是绿灯,黑代表是红灯)

我们发现Lamp类中灯对象以及对象个数是确定的,无论在程序的什么地方去获得某个方向的灯时,每次获得的都是同一个实例对象,所以Lamp类改用枚举来做显然具有很大的方便性,永远都只有代表12个方向的灯的实例对象,所以我们把Lamp类设计为枚举类。

1、首先,我们知道十字路口右转弯的路线是不受灯控制的,但是为了程序采用统一的处理方式,我们假定4个右转弯灯是长绿状态。

2、然后剩下的8个灯可以分为4对。每成对的两个灯,我们理解为反向的两个灯。成对灯变亮或者变黑都是一致的。

3、这样就把灯简化为4个,这4个灯依次循环变亮。例如:1号灯-->2号灯-->3号灯-->4号灯-->1号灯

4、并且我们要在当前灯变黑的时候,都要伴随着下一个灯的变亮。

5、每个交通灯还要有变黑、变亮的方法,并且还要有表示自己的亮黑状态的方法。

需要注意的是:

1、除了右转弯的4个灯对象初始值是亮(true)的状态,其他都为黑(false)的状态,并且"S2N","S2W","E2W","E2S"只有这4个灯设置有反向灯(opposite),如果它们的反向灯也设置有反向灯,这4个灯调用light()方法时,会出现死循环。灯的亮黑状态只需要在这4个之间循环,所以只有这4个灯有下一个灯(next)。

2、"S2N","S2W","E2W","E2S"4条路线的灯,在创建对象时接收opposite(反向灯)和next(下一个灯),不能接受灯对象,因为在接收时,反向灯和下一个灯可能还没有被创建。所以只接收灯的字符串表示形式,再使用枚举的valueOf()方法将字符串转换为对应名称的Lamp对象。

Lamp类的代码示例:

package com.itheima.traffic;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 boolean lighted;//表示灯的亮黑状态:true代表灯是Green,flase代表灯是Redprivate String opposite;//以字符串形式表示反向灯名称private String next;//以字符串形式表示下一个灯名称private Lamp(String opposite,String next,boolean lighted){this.opposite = opposite;this.next = next;this.lighted = lighted;}//该方法返回灯的亮黑状态public boolean isLighted(){return lighted;}//把灯变亮的方法(把lighted变量设置为true),如果有反向灯,把反向灯也同时变亮public void light(){this.lighted = true;if(opposite != null){//把字符串表示的灯名称转化为灯对象,同时调用变亮方法。Lamp.valueOf(opposite).light();}//打印出哪个方向的灯变绿了。System.out.println(this.name()+"lamp is green,下边应该有6个方向的汽车通过!");}//把灯变黑的方法(把lighted变量设置为false),如果有反向灯,把反向灯也同时变黑。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;}}

Road类的创建:

1、我们知道路上有车辆:vechicles,所以路就要有提供操作这些车的方法,比如:增加车(车来到十字路口),减少车(车开过十字路口)。所以操作车的方法是路提供的,但是此系统并不研究车移动的过程,只是捕捉出车辆穿过路口的过程,也就是要捕捉路上减少一辆车的过程,所以,这个车并不需要单独设计成为一个对象,用一个字符串表示就可以了,把字符串表示的车的名字作为路的成员数据。然后我们把若干字符串表现的车存放在一个集合中,该集合作为Road类的私有成员数据。

2、创建一个单线程,在线程中提交一个任务,该任务负责随机向集合中上添加车,来模拟车开到十字路口。

3、创建一个定时器(线程池),负责在给定的延迟后,定期的指定命令。负责每隔1秒从集合中移除一个元素,来模拟车开过十字路口。

Road类的代码示例:

package com.itheima.traffic;import java.util.ArrayList;import java.util.List;import java.util.Random;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.ScheduledExecutorService;import java.util.concurrent.TimeUnit;public class Road {//Road中字符串形式表示成员数据:vechiclesprivate String name = null;//定义一个vechicles集合,便于控制车的增加和减少。private List<String> vechicles = new ArrayList<String>();//Road对象在创建的时候,就要接收路的名字(每创建一条路线的时候,给路线指定一个名字)public Road(String name){this.name = name;//在构造时创建创建一个使用单个 worker 线程的 Executor。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) {e.printStackTrace();}//向vechicles车辆集合中添加车的名字:路线方向_序号vechicles.add(Road.this.name+"_"+i);}}});//创建一个线程数为1的线程池,它执行的任务是判断条件,从集合中移除元素(车辆开过路口)。ScheduledExecutorService timer = Executors.newScheduledThreadPool(1);timer.scheduleAtFixedRate(new Runnable(){public void run(){if(vechicles.size()>0){//把路线对应的字符串名字转化为Lamp对象。(此刻加载Lamp类)boolean lighted = Lamp.valueOf(Road.this.name).isLighted();//当该灯的isLighted()方法返回true时,说明该路线是绿灯,车辆通行。if(lighted){//remove()方法的返回值类就是移除元素的类型,所以在这里返回的就会是被移走的车(以字符串形式表现出来。)System.out.println(vechicles.remove(0)+"is travering!");}}}}, 1, 1, TimeUnit.SECONDS);}}

LampController类的创建:

1、所谓灯控制器就是控制灯的状态,所以要设置某个方向的灯作为当前灯此处是(currentLamp = Lamp.S2N),并且让它变亮。

2、创建一个定时器(线程池),它执行的任务是定时的把当前灯变黑让向下一个灯变亮,同时把下一个灯赋给当前灯,

以这种方式来完成灯之间的循环切换。

LampController类的代码示例:

package com.itheima.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;//让S2N方向的灯首次作为当前灯currentLamp.light();//把当前灯置为亮//创建一个线程数为1的线程池,它负责在给定的时间间隔内,切换灯的亮与黑ScheduledExecutorService timer = Executors.newScheduledThreadPool(1);timer.scheduleAtFixedRate(new Runnable(){public void run(){currentLamp = currentLamp.blackOut();//当前灯变黑后,让下一个灯变亮,同时返回下一个灯并赋给当前灯。}}, 10, //首次执行的延迟时间10, //连续执行之间的周期:每隔10秒灯切换行一次TimeUnit.SECONDS);}}

MainClass类的执行:

1、创建12方向的12个Road对象,对象一旦创建,每条路线上开始随机(1~10秒)循环的加入车辆(1~999个)。因为此时4条右转弯灯是常亮的,所以这4个对象一旦创建,就开始有车通过路口,用打印移除集合元素返回元素名称的方式来表示通过路口的车辆名称。车辆名称为:方向_序号。

2、创建一个LampController对象,对象一旦创建,就把从南向北"S2N"方向以及从北向南"N2S"方向的灯变亮,车辆开始通过。10秒后切换灯,"S2N"和"N2S"方向的灯变黑,"S2W"以及反向路线"N2E"灯变量,车辆开始通过。每隔10秒切换下一个灯,并一直循环,完成十字路口交通灯系统的模拟。

MainClass类的代码示例:

package com.itheima.traffic;public class MainClass {public static void main(String[] args) {String [] directions = new String[]{"S2N","S2W","E2W","E2S","N2S","N2E","W2E","W2N","S2E","E2N","N2W","W2S"};//创建12方向的12个Road对象for(int i=0;i<directions.length;i++){new Road(directions[i]);}//创建灯的控制器,用以开启亮灯和切换灯new LampController();}}

为避免误导初学者,本博客如有错误或者不严谨的地方,请在下方给予评论,以便及时修改!谢谢... ...

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

详细请查看:www.itheima.com

0 0
原创粉丝点击