控制框架是一类特殊的应用程序框架(应用程序框架是被设计用以解决某类特定问题的一个类或一组类),它用来解决响应事件的需求,主要用来响应事件的系统被称作事件驱动系统(Java Swing 库就是一个控制框架,优雅地解决了 GUI 的问题)。
要实现控制框架通常需要运用设计模式中的模版方法,模版方法包含算法的基本结构,并且会调用一个或多个可覆盖的方法,以完成算法动作,这样做可将变化的事物与保持不变的事物分离开。
控制框架的工作就是在事件“就绪”的时候执行事件,“就绪”可以是任何条件,我们假设就绪条件是基于时间触发的事件,来实现一个温室控制框架来控制灯光、水、温度调节器的开关,以及响铃和重启系统,每个行为都是完全不同的,使用控制框架可以容易地分离这些代码。
首先我们得定义一个接口描述要控制的事件,因其内部还需要定义基于时间去执行控制的方法,所以使用抽象类代替实际的接口。
在构造器内指定事件的延迟生效时间 delayTime ;start() 方法用于重置计时器,如果想要重置时间,只需再次调用 start() 方法即可; ready() 方法告诉我们何时可以调用 action() 方法。
public abstract class Event {
//事件生效时间
private long eventTime;
//事件延迟时间
protected final long delayTime;
public Event(long delayTime) {
this.delayTime = delayTime;
}
//启动事件
public void start() {
eventTime = System.nanoTime() + delayTime;
}
//判断事件是否就绪
public boolean ready() {
return System.nanoTime() >= eventTime;
}
//具体需要执行的行为
public abstract void action();
}
接下来再来定义一个用来管理并触发事件的实际控制框架 Controller 。
通过 addEvent() 方法将 Event 对象被储存在 eventList 中;
run() 方法 通过 foreach 连续获取 eventList 中的 Event ,当 ready() 方法达成执行条件时,调用 Event 的 action() 方法,并通过 remove() 移除元素(一般是不能在 foreach 中移除元素的,new ArrayList<>(eventList) 相当于在每次循环开始前,把原有的集合重新排列成一个新的集合,故能在此循环中移除元素)。
下一步便可以通过控制框架 Controller 生成一个具体的应用程序框架 GreenhouseControls 类代表温室控制系统。
public class GreenhouseControls extends Controller {
//灯光状态
private boolean light = false;
//打开灯光控制类
public class LightOn extends Event {
public LightOn(long delayTime) {
super(delayTime);
}
@Override
public void action() {
light = true;
}
public String toString() {
return "Light is on";
}
}
//关闭灯光控制类
public class LightOff extends Event {
public LightOff(long delayTime) {
super(delayTime);
}
@Override
public void action() {
light = false;
}
public String toString() {
return "Light is off";
}
}
//水开关状态
private boolean water = false;
//打开水开关控制类
public class WaterOn extends Event {
public WaterOn(long delayTime) {
super(delayTime);
}
@Override
public void action() {
water = true;
}
public String toString() {
return "Greenhouse water is on";
}
}
//关闭水开关控制类
public class WaterOff extends Event {
public WaterOff(long delayTime) {
super(delayTime);
}
@Override
public void action() {
water = false;
}
public String toString() {
return "Greenhouse water is off";
}
}
//温度调节器状态
private String thermostat = "Day";
//温度调节器夜间模式控制类
public class ThermostatNight extends Event {
public ThermostatNight(long delayTime) {
super(delayTime);
}
@Override
public void action() {
thermostat = "night";
}
public String toString() {
return "ThermostatDay on night setting";
}
}
//温度调节器日间模式控制类
public class ThermostatDay extends Event {
public ThermostatDay(long delayTime) {
super(delayTime);
}
@Override
public void action() {
thermostat = "Day";
}
public String toString() {
return "ThermostatDay on day setting";
}
}
//响铃控制类
public class Bell extends Event {
public Bell(long delayTime) {
super(delayTime);
start();
}
@Override
public void action() {
addEvent(new Bell(delayTime));
}
public String toString() {
return "Bing!";
}
}
//重启系统控制类
public class Restart extends Event {
private Event[] eventList;
public Restart(long delayTime, Event[] eventList) {
super(delayTime);
this.eventList = eventList;
for (Event event : eventList) {
addEvent(event);
}
}
@Override
public void action() {
for (Event event : eventList) {
event.start();
addEvent(event);
}
start();
addEvent(this);
}
public String toString() {
return "Restarting system";
}
}
//关闭系统控制类
public static class Terminate extends Event {
public Terminate(long delayTime) {
super(delayTime);
start();
}
@Override
public void action() {
System.exit(0);
}
public String toString() {
return "Terminating";
}
}
}
根据具体需求在 GreenhouseControls 实现多个不同的 Event 内部类,代表温室系统的不同行为。
light 、water、thermostat 字段都属于外围类 GreenhouseControls ,所有的内部类都可以访问修改这些字段。每个 Event 类基本都是一致的,但 Bell、Restart、Terminate 比较特殊。
Bell 类会在每次执行 action() 方法后将自身重新添加回 eventList 中等待再次执行;
Restart 类将一组 Event 对象加入到控制框架 GreenhouseControls 中,使系统能够有规律的重启自身;
Terminate 类用于关闭应用程序,当添加纳秒数作为命令行参数后,达到指定时间后,程序会自动终止。
idea 可在下图所示位置添加命令行参数。
最后创建 GreenhouseController 类来添加不同的 Event 对象来初始化系统,接下来就可以运行程序看看最终的效果。
public class GreenhouseController {
public static void main(String[] args) {
GreenhouseControls gc = new GreenhouseControls();
gc.addEvent(gc.new Bell(900));
Event[] eventList = {
gc.new ThermostatNight(0),
gc.new LightOn(200),
gc.new LightOff(400),
gc.new WaterOn(600),
gc.new WaterOff(800),
gc.new ThermostatDay(1400)
};
gc.addEvent(gc.new Restart(2000, eventList));
if (args.length == 1) {
gc.addEvent(new GreenhouseControls.Terminate(new Integer(args[0])));
}
gc.run();
}
}
Bing!
ThermostatDay on night setting
Light is on
Light is off
Greenhouse water is on
Greenhouse water is off
ThermostatDay on day setting
Restarting system
Terminating
本次分享至此结束,希望本文对你有所帮助,若能点亮下方的点赞按钮,在下感激不尽,谢谢您的【精神支持】。
若有任何疑问,也欢迎与我交流,若存在不足之处,也欢迎各位指正!