Паттерн «Команда»
Часть раздела Объектно-ориентированное программирование путешествия по Java на Coddy — урок 70 из 87.
Паттерн Команда — это поведенческий паттерн проектирования, который превращает запрос в самостоятельный объект, содержащий всю информацию о запросе. Такая трансформация позволяет передавать запросы в качестве аргументов методов, откладывать или ставить выполнение запроса в очередь, а также поддерживать операции отмены.
Представьте это как ресторан: вместо того чтобы напрямую говорить шеф-повару, что приготовить, вы записываете свой заказ на листке. Официант (invoker) относит листок (command) на кухню, где его можно поставить в очередь, приоритизировать или даже отменить. Этот паттерн отделяет объект, инициирующий операцию, от объекта, который её выполняет.
Паттерн состоит из четырех ключевых компонентов: интерфейс Command, объявляющий метод execute, классы ConcreteCommand, реализующие конкретные действия, Receiver, который выполняет фактическую работу, и Invoker, который запускает команды:
interface Command {
void execute();
}class Light { // Получатель
public void turnOn() {
System.out.println("Light is ON");
}
public void turnOff() {
System.out.println("Light is OFF");
}
}class LightOnCommand implements Command {
private Light light;
public LightOnCommand(Light light) {
this.light = light;
}
public void execute() {
light.turnOn();
}
}class RemoteControl { // Инициатор
private Command command;
public void setCommand(Command command) {
this.command = command;
}
public void pressButton() {
command.execute();
}
}Вызывающий объект не знает, какое действие будет выполнено — он просто вызывает execute():
Light light = new Light();
Command lightOn = new LightOnCommand(light);
RemoteControl remote = new RemoteControl();
remote.setCommand(lightOn);
remote.pressButton(); // Вывод: Свет ВКЛЮЧЕНПаттерн Команда отлично подходит в тех случаях, когда вам нужно ставить операции в очередь, реализовать функциональность отмены и повтора действий или планировать задачи для последующего выполнения. Каждая команда инкапсулирует всё необходимое для выполнения действия, делая вашу систему более гибкой и расширяемой.
Задание
ЛегкоДавайте создадим систему автоматизации умного дома, используя паттерн Команда (Command Pattern)! Вы создадите систему, в которой различными домашними устройствами можно управлять с помощью команд, что позволяет ставить действия в очередь, выполнять их и даже сохранять для последующего использования — прямо как универсальный пульт дистанционного управления, которому не нужно знать, как каждое устройство работает внутри.
Вы организуете свой код в четырех файлах:
Command.java: Определите интерфейсCommand, который будут реализовывать все команды устройств. Он должен объявлять один методexecute(), который выполняет действие команды.Devices.java: Создайте два класса-получателя (receiver), представляющих устройства умного дома:Television— имеет методыpowerOn(), который выводит"TV is now ON",powerOff(), который выводит"TV is now OFF", иsetChannel(int channel), который выводит"TV channel set to "плюс значение канала.Thermostat— имеет методыsetTemperature(int temp), который выводит"Thermostat set to "плюс значение температуры и" degrees", иturnOff(), который выводит"Thermostat turned OFF".Commands.java: Создайте конкретные классы команд, которые инкапсулируют операции устройств:TVOnCommand— принимаетTelevisionв конструкторе и вызываетpowerOn()при выполнении.TVOffCommand— принимаетTelevisionв конструкторе и вызываетpowerOff()при выполнении.TVChannelCommand— принимаетTelevisionиint channelв конструкторе и вызываетsetChannel()с этим каналом при выполнении.ThermostatSetCommand— принимаетThermostatиint temperatureв конструкторе и вызываетsetTemperature()с этим значением при выполнении.Main.java: Создайте классRemoteControl(инициатор/invoker), который имеет методsetCommand(Command cmd)для хранения команды иpressButton()для выполнения сохраненной команды.В методе main вы получите два входных значения: номер ТВ-канала (целое число) и температуру термостата (целое число).
Создайте объекты
TelevisionиThermostat. СоздайтеRemoteControlи продемонстрируйте работу паттерна Команда:- Установите
TVOnCommandи нажмите кнопку - Установите
TVChannelCommandс введенным каналом и нажмите кнопку - Установите
ThermostatSetCommandс введенной температурой и нажмите кнопку - Установите
TVOffCommandи нажмите кнопку
- Установите
Вы получите два входных значения по порядку: ТВ-канал (целое число) и температуру термостата (целое число).
Например, при входных данных 5 и 72 ваш вывод будет следующим:
TV is now ON
TV channel set to 5
Thermostat set to 72 degrees
TV is now OFFОбратите внимание, что RemoteControl никогда не взаимодействует с устройствами напрямую — он знает только об интерфейсе Command. Каждая команда инкапсулирует все необходимое для выполнения своего действия, что позволяет легко добавлять новые устройства и команды без изменения инициатора!
Попробуйте сами
import java.util.Scanner;
// TODO: Создайте класс RemoteControl (инициатор) с:
// - методом setCommand(Command cmd) для сохранения команды
// - методом pressButton() для выполнения сохраненной команды
class RemoteControl {
// TODO: Реализуйте RemoteControl
}
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Чтение входных данных
int channel = scanner.nextInt();
int temperature = scanner.nextInt();
// TODO: Создайте Television и Thermostat
// TODO: Создайте RemoteControl
// TODO: Продемонстрируйте паттерн Command:
// 1. Установите TVOnCommand и нажмите кнопку
// 2. Установите TVChannelCommand с введенным каналом и нажмите кнопку
// 3. Установите ThermostatSetCommand с введенной температурой и нажмите кнопку
// 4. Установите TVOffCommand и нажмите кнопку
scanner.close();
}
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыВведение в ООПКлассы и объектыКлючевое слово thisМетодыПоля (атрибуты)Метод-конструкторПерегрузка конструкторовИтоги — Простой калькулятор4Наследование
Основы наследования (extends)Ключевое слово superПереопределение методов (@Override)Цепочка конструкторовКласс ObjectОдиночное и многоуровневое наследованиеПочему нет множественного наследования классовИтоги — Иерархия сотрудников7Специальные методы и класс Object
Метод toString()equals() и hashCode()Метод clone()compareTo() и ComparableИнтерфейс ComparatorПовторение — Кастомная сортировка2Модификаторы доступа и инкапсуляция
Обзор уровней доступаМетоды геттеры и сеттерыСокрытие данныхКлючевое слово finalИтоги — Менеджер банковского счета5Полиморфизм
Основы перегрузки методовПереопределение методов (Run-Time)Upcasting и DowncastingОператор instanceofАбстрактные классы и методыИтоги: Калькулятор фигур8Продвинутые концепции ООП
Композиция против наследованияАгрегация против композицииВнутренние, вложенные и анонимные классыEnums и методы перечисленийRecords (Java 16+)Sealed-классы (Java 17+)11Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonПаттерн FactoryПаттерн BuilderПаттерн ObserverПаттерн Strategy3Свойства класса и статические члены
Переменные экземпляра и статические переменныеСтатические методыСтатические блокиКонстанты (static final)Итоги: Счетчик и утилиты6Интерфейсы и абстрактные классы
Введение в интерфейсыРеализация интерфейсовРеализация нескольких интерфейсовDefault и Static методы в интерфейсахАбстрактные классы vs ИнтерфейсыФункциональные интерфейсыИтоги — Платежная система9Обобщения
Введение в обобщенияОбобщенные классыОбобщенные методыОграниченные параметры типаСимволы подстановки (Wildcards: ?, extends, super)Итоги — Обобщенный контейнер12Паттерны проектирования. Часть 2
Паттерн «Команда»Паттерн «Адаптер»Паттерн «Декоратор»Паттерн «Шаблонный метод»Паттерн «Состояние»Паттерн «Компоновщик»Паттерн «Итератор»