82
Рассмотрим конкретную реализацию системы управления, разработанную для управления функциями оранжереи
[3]
. Все события — включение света, воды и нагревателей, звонок и перезапуск системы — абсолютно разнородны. Однако система управления разработана так, что различия в коде легко изолируются. Внутренние классы помогают унаследовать несколько производных версий одного базового класса Event в пределах одного класса. Для каждого типа события от Event наследуется новый внутренний класс, и в его реализации action() записывается управляющий код.
Как это обычно бывает при использовании каркасов приложений, класс GreenhouseControls наследует от класса Controller:
//: innerclasses/GreenhouseControls.java // Пример конкретного приложения на основе системы // управления, все находится в одном классе. Внутренние // классы дают возможность инкапсулировать различную // функциональность для каждого отдельного события, import innerclasses.control 1er.*,
public class GreenhouseControls extends Controller {
private boolean light = false,
public class LightOn extends Event {
public LightOndong delayTime) { super (delayTime). } public void actionO {
// Сюда помещается аппаратный вызов, выполняющий // физическое включение света, light = true;
}
public String toStringO { return "Свет включен"; }
}
public class LightOff extends Event {
public LightOffdong delayTime) { super(delayTime); } public void actionO {
// Сюда помещается аппаратный вызов, выполняющий // физическое выключение света light = false;
}
public String toStringO { return "Свет выключен", }
}
private boolean water = false;
public class WaterOn extends Event {
public WaterOn(long delayTime) { super(delayTime), } public void actionO {
// Здесь размещается код включения '// системы полива, water = true;
}
public String toStringO {
return "Полив включен";
}
}
public class WaterOff extends Event {
public WaterOffdong delayTime) { super(delayTime); } public void actionO {
// Здесь размещается код выключения // системы полива water = false;
}
public String toStringO {
return "Полив отключен";
}
}
private String thermostat = "День";
public class Thermostaticght extends Event {
public Thermostaticght(long delayTime) { super(delayTime);
}
public void actionO {
// Здесь размещается код управления оборудованием thermostat = "Ночь";
public String toStringO {
return "Термостат использует ночной режим";
}
}
public class ThermostatDay extends Event {
public ThermostatDay(long delayTime) { super(delayTime);
}
public void actionO {
// Здесь размещается код управления оборудованием thermostat = "День";
}
public String toStringO {
return "Термостат использует дневной режим";
}
}
// Пример метода actionO, вставляющего
// самого себя в список событий.
public class Bell extends Event {
public Bell(long delayTime) { super(delayTime); } public void actionO {
addEvent(new Bell(delayTime));
}
public String toStringO { return "Бам!"; }
}
public class Restart extends Event { private Event[] eventList;
public Restartdong delayTime. Event[] eventList) { super(delayTime); this.eventList = eventList; for(Event e : eventList) addEvent(e);
}
public void actionO {
for(Event e : eventList) {
e. start О; // Перезапуск каждый раз addEvent(e);
}
startO; // Возвращаем это событие Event addEvent(this);
}
public String toStringO {
return "Перезапуск системы";
}
}
public static class Terminate extends Event {
public Terminatedong delayTime) { super(delayTime); }
public void actionO { System.exit(0); }
public String toStringO { return "Отключение"; }
}
} ///;-
Заметьте, что поля light, thermostat и ring принадлежат внешнему классу GreenhouseControls, и все же внутренние классы имеют возможность обращаться к ним, не используя особой записи и не запрашивая особых разрешений. Большинство методов action() требует управления оборудованием оранжереи, что, скорее всего, привлечет в программу сторонние низкоуровневые вызовы.
В основном классы Event похожи друг на друга, однако классы Bell и Restart представляют собой особые случаи. Bell выдает звуковой сигнал и добавляет себя в список событий, чтобы звонок позднее сработал снова. Заметьте, что внутренние классы действуютпочтикак множественное наследование: классы Bell и Restart имеют доступ ко всем методам класса Event, а также ко всем методам внешнего класса GreenhouseControls.
Классу Restart передается массив объектов Event, которые он добавляет в контроллер. Так как Restart также является объектом Event, вы можете добавить этот объект в список событий в методе Restart.action(), чтобы система регулярно перезапускалась.
Следующий класс настраивает систему, создавая объект GreenhouseControls и добавляя в него разнообразные типы объектов Event. Это пример шаблона проектирования «команда»— каждый объект в EventList представляет собой запрос, инкапсулированный в объекте:
//: с08:GreenhouseControl1er.java // Настраивает и запускает систему управления. // {Args: 5000}
import innerclasses.control 1er.*:
public class GreenhouseController {
public static void main(String[] args) {
GreenhouseControls gc = new GreenhouseControls(); // Вместо жесткого кодирования фиксированных данных // можно было бы считать информацию для настройки // из текстового файла: gc.addEvent(gc.new Bel 1 (900)): Event[] eventList = {
gc.new ThermostatNight(O), gc.new Light0n(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.runO;
}
} * Output: Вам!
Термостат использует ночной режим
Свет включен
Свет выключен
Полив включен
Полив отключен
Термостат использует дневной режим Перезапуск системы Отключение ///:-
Класс инициализирует систему, включая в нее нужные события. Если передать программе параметр командной строки, она завершается по истечении заданного количества миллисекунд (используется при тестировании). Конечно, чтобы программа стала более гибкой, описания событий следовало бы не включать в программный код, а загружать из файла.