JavaSE(12):之交通灯管理系统


交通灯管理系统

 

1、知识准备:面向对象编程的要点——类设计经验

要点:数据属于谁,谁来操作数据,就将谁设计成一个类。

实例:

1)球沿着线滚动:滚动是球自身的方法,需要用到一条线,那么线可以作为球的一个属性。线提供了两个点,点是线的数据,那么线可以封装成一个类,拥有两个属性,起点和终点,同时提供一个根据当前点返回终点方法。那么整个过程就是球调用其内部属性线的方法获得终点,然后球调用自身的方法,滚动到终点。

2)两个石头磨成石刀,石刀砍树得到木材,木材变成凳子。注意一点:石头磨成石刀之后,石头就没有了,木材变成凳子之后,木材就没有了,所以不能将石头变成石刀设置成石头的一个方法,若一个类的方法会让自己的对象消失变成其他对象,这不和逻辑也不好实现。只能这样。创建一个石刀工厂,提供一个生成石刀的工厂方法,传入两个石头类对象作为参数,返回一个石刀类对象。石刀具有伐木方法,传入一个树对象,返回一个木材对象。然后建立一个凳子工厂,提供一个参数为木材,返回凳子的工厂方法。

 

2、交通灯系统的分析

线路:一个路口有3种线路,总共3*4=12种线路,但是右转线路忽略,那么默认让右转永远可行,即假象右转有个灯永远为绿。根据这种思路,12条线路就有12个交通灯,那么灯是固定的,用枚举实现。同时可以发现剩下的8种线路有个对称关系,就是交通线路中,南往北通,那么必定北往南也通,所以只需考虑4条线路,对应的4条线路也就跟着运行就可以了。此处,主要操作:南直走向北S->N,南左转向西S->W,东直走向西E->W,东左转向南E->S

类设计:

Lamp:灯封装成一个类,包含灯的线路信息,就是该灯是哪条线的,灯的状态情况亮灭,同时设置亮灭的方法。根据交通规则,要设定交通灯绿灯亮起的次序,此处按这个顺序:S->N10秒,南北走向通车10秒,灯灭同时S->W10秒,上行车辆左转,下行线路右转。然后E->W,然后是E->S,这个灯亮的次序用一个灯的控制器类完成,但是需要知道灯的下一个灯,以实现本灯灭,下一个灯亮的操作,所以灯类需要设置一个属性,下一个灯,同时还需要一个属性,对称线路的灯。注:此系统简化,灯亮表示绿灯亮,灯灭表示红灯状态。

LampControler:灯的控制器:完成灯的流水控制,实现依次点亮灯功能,默认开始点亮一个灯,然后开始取出这个灯的下一个灯10秒后,原灯灭,下一灯亮,采用定时器循环操作。

Road:道路类,需要设置属性:线路的方向,需要设置一个集合:存放路上的车。需要完成功能:车的增加和减少。增加随机时间间隔增加,通过线程操作。减少,需要查看该线路方向的灯状态,若灯为亮,且路上有车,则车每个1秒少一辆,通过定时器操作。

 

补充知识:线程工具类的使用Executors,提供线程池、定时器的创建

 

具体实现代码:(包含四个文件,并对张孝祥老师的代码做出改动)

package blog12Traffic;

public enum Lamp {
	S2N("S2W","N2S",false),S2W("E2W","N2E",false),E2W("E2S","W2E",false),E2S("S2N","W2N",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);/*四条常亮的右转线路,true设为常亮*/
	
	private String nextLamp = null;//下一个灯
	private String opposite = null;//对称线路的灯,本应用Lamp类型的,但是此处使用String,再用枚举类的valueOf根据字符串取注同名枚举对象即可
	private boolean lighted = false;//灯的亮灭状态,默认为灭
	
	private Lamp(String nextLamp,String opposite,boolean lighted){
		this.nextLamp = nextLamp;
		this.opposite = opposite;
		this.lighted = lighted;
	}
	
	public boolean isLight(){
		return lighted; //返回灯的状态
	}
	
	public void light(){
		lighted = true;
		if(opposite!=null){
			Lamp.valueOf(opposite).light(); 
			//可见这是个嵌套调用,如果对称的那个灯还设置对称灯参数的话,就会无线运行,堆栈溢出
		}
		System.out.println("方向:" + this.name() + " 的绿灯亮起了,该线路通车,此时共6条线路通车...");
	}
	
	public Lamp turnOff(){
		//熄灭该灯,及该对称方向上的灯,同时点亮下一个线路方向的灯
		lighted = false;
		System.out.println( "绿灯:" + this.name() + " 熄灭了...");
		if(opposite!=null){
			Lamp.valueOf(opposite).turnOff();
		}

		Lamp nextlamp = null;
		if(nextLamp!=null){ //此处必须进行判断,因为实际上执行一次turnOff方法,会有两个对象来执行这段代码,比如S2N和N2S
			nextlamp = Lamp.valueOf(nextLamp);//而S2N是有nextLamp的,N2S是没有nextLamp的,所以要判断nextLamp
			nextlamp.light();
		}
		return nextlamp;
	}
}



package blog12Traffic;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

//灯的控制器类,实现灯的定时逐次点亮功能
public class LampControler {
	
	private Lamp currentLamp = null;//当前亮起来的灯
	
	
	public LampControler(){
		currentLamp = Lamp.S2N;//创建控制器时,默认先让S->N的灯先亮
		currentLamp.light();
		
		//开始定时器操作,循环逐次点亮了,使用工具类Executors
		ScheduledExecutorService timer =Executors.newScheduledThreadPool(1);//建立一个定时器线程,内涵一个线程
		timer.scheduleAtFixedRate(/*按固定频率执行*/
				new Runnable(){/*执行内容,实现runnable接口,重写run方法,算是一个线程对象*/
					@Override
					public void run() {/*在run中实现逐次亮灭*/
						currentLamp = currentLamp.turnOff();//熄灭当前亮的,返回紧接着亮起来的,循环操作,这就是turnOff设置返回值的好处
					}	
				}, 
				10/*初始延时时间,第一次启动之前延时时间*/,
				10/*周期*/, 
				TimeUnit.SECONDS/*设置上面两个参数的取值类型,为秒*/);
	}
}


package blog12Traffic;

import java.util.ArrayList;
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 {
	private String direction = null; //方向
	private ArrayList<String> vechicles = new ArrayList<String>();
	
	public Road(String direction){
		this.direction = direction;
		
		//随机增加车辆,线程实现,也可以用定时器循环不停增加车辆,但是时间间隔相同,不符实况
		ExecutorService thread = Executors.newSingleThreadExecutor();//创建一个单线程的线程池
		thread.execute(new Runnable(){
			@Override
			public void run() {
				for(int i=1;i<1000;i++){//设总共增加999辆车
					try {
						Thread.sleep( (new Random().nextInt(10)+1)*1000 );//nextInt(10),返回0—9
					} catch (InterruptedException e) {
						e.printStackTrace();
					} 
					vechicles.add(Road.this.direction + "方向第" + i + "辆车");
				}
			}});
		
		//每隔一秒检查该方法上路灯情况,绿灯则减少一辆车,定时器实现
		ScheduledExecutorService timer = Executors.newScheduledThreadPool(1);
		timer.scheduleAtFixedRate(
				new Runnable(){
					@Override
					public void run() {
						if(vechicles.size()>0){//路上有车
							boolean light = Lamp.valueOf(Road.this.direction).isLight(); //该路线方向上灯亮了吗
							if(light){
								System.out.println(vechicles.remove(0) + " 通过了十字路口...");//此处remove返回的就是删除的那个元素
							}
						}
					}}, 
				1, 
				1, 
				TimeUnit.SECONDS);
		
	}
}


package blog12Traffic;

public class TrafficSystem {
	public static void main(String[] args) {
		//产生灯控制器,最好先,灯控制器,因为道路调用到灯控制器,所以,控制器最好在路之前产生
		new LampControler();
		//构造12条线路
		String[] roadName = {"2N","S2W","E2W","E2S","N2S","N2E","W2E","W2N","S2E","E2N","N2W","W2S"};
		for(int i=0;i<roadName.length;i++){
			new Road(roadName[i]);
		}
	}
}


输出实例:

方向:N2S 的绿灯亮起了,该线路通车,此时共6条线路通车...
方向:S2N 的绿灯亮起了,该线路通车,此时共6条线路通车...
E2N方向第1辆车 通过了十字路口...
N2S方向第1辆车 通过了十字路口...
W2S方向第1辆车 通过了十字路口...
E2N方向第2辆车 通过了十字路口...
N2W方向第1辆车 通过了十字路口...
E2N方向第3辆车 通过了十字路口...
绿灯:S2N 熄灭了...
绿灯:N2S 熄灭了...
方向:N2E 的绿灯亮起了,该线路通车,此时共6条线路通车...
方向:S2W 的绿灯亮起了,该线路通车,此时共6条线路通车...
N2W方向第2辆车 通过了十字路口...
S2E方向第1辆车 通过了十字路口...
N2E方向第1辆车 通过了十字路口...
S2W方向第1辆车 通过了十字路口...
S2W方向第2辆车 通过了十字路口...
W2S方向第2辆车 通过了十字路口...
N2W方向第3辆车 通过了十字路口...
N2E方向第2辆车 通过了十字路口...
S2W方向第3辆车 通过了十字路口...
E2N方向第4辆车 通过了十字路口...
E2N方向第5辆车 通过了十字路口...
W2S方向第3辆车 通过了十字路口...
S2E方向第2辆车 通过了十字路口...
绿灯:S2W 熄灭了...
绿灯:N2E 熄灭了...
方向:W2E 的绿灯亮起了,该线路通车,此时共6条线路通车...
方向:E2W 的绿灯亮起了,该线路通车,此时共6条线路通车...
E2W方向第1辆车 通过了十字路口...
W2E方向第1辆车 通过了十字路口...
E2W方向第2辆车 通过了十字路口...
S2E方向第3辆车 通过了十字路口...
W2E方向第2辆车 通过了十字路口...
W2S方向第4辆车 通过了十字路口...
W2E方向第3辆车 通过了十字路口...
E2W方向第3辆车 通过了十字路口...
N2W方向第4辆车 通过了十字路口...
E2N方向第6辆车 通过了十字路口...
W2S方向第5辆车 通过了十字路口...
W2E方向第4辆车 通过了十字路口...
E2N方向第7辆车 通过了十字路口...
W2E方向第5辆车 通过了十字路口...
绿灯:E2W 熄灭了...
绿灯:W2E 熄灭了...
方向:W2N 的绿灯亮起了,该线路通车,此时共6条线路通车...
方向:E2S 的绿灯亮起了,该线路通车,此时共6条线路通车...
E2S方向第1辆车 通过了十字路口...
W2N方向第1辆车 通过了十字路口...
W2S方向第6辆车 通过了十字路口...
E2S方向第2辆车 通过了十字路口...
W2N方向第2辆车 通过了十字路口...
S2E方向第4辆车 通过了十字路口...
E2S方向第3辆车 通过了十字路口...
N2W方向第5辆车 通过了十字路口...
E2N方向第8辆车 通过了十字路口...
W2N方向第3辆车 通过了十字路口...
E2S方向第4辆车 通过了十字路口...
W2N方向第4辆车 通过了十字路口...
E2S方向第5辆车 通过了十字路口...


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值