82

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: Вам!

Термостат использует ночной режим

Свет включен

Свет выключен

Полив включен

Полив отключен

Термостат использует дневной режим Перезапуск системы Отключение ///:-

Класс инициализирует систему, включая в нее нужные события. Если пере­дать программе параметр командной строки, она завершается по истечении за­данного количества миллисекунд (используется при тестировании). Конечно, чтобы программа стала более гибкой, описания событий следовало бы не вклю­чать в программный код, а загружать из файла.