Menu
Coddy logo textTech

Паттерн «Команда»

Часть раздела Объектно-ориентированное программирование путешествия по Java на Coddy. Урок 70 из 87.

Command Pattern — это поведенческий шаблон проектирования, который преобразует запрос в самостоятельный объект, содержащий всю информацию о запросе. Это преобразование позволяет передавать запросы в качестве аргументов метода, откладывать или ставить выполнение запроса в очередь, а также поддерживать операции, которые можно отменить.

Представьте это как ресторан: вместо того чтобы напрямую говорить повару, что приготовить, вы записываете свой заказ на бланке. Официант (invoker) относит бланк (command) на кухню, где его можно поставить в очередь, расставить по приоритету или даже отменить. Этот паттерн отделяет объект, который вызывает операцию, от объекта, который её выполняет.

У этого паттерна есть четыре ключевых компонента: интерфейс Command, объявляющий метод execute, классы ConcreteCommand, реализующие конкретные actions, 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();
    }
}

Invoker не знает, какое действие будет выполнено. Он просто вызывает execute():

Light light = new Light();
Command lightOn = new LightOnCommand(light);

RemoteControl remote = new RemoteControl();
remote.setCommand(lightOn);
remote.pressButton();  // Вывод: Light is ON

Паттерн Command особенно эффективен, когда вам нужно поставить операции в очередь, реализовать функцию отмены/повтора или запланировать задачи для последующего выполнения. Каждая команда инкапсулирует всё необходимое для выполнения действия, делая вашу систему более гибкой и расширяемой.

challenge icon

Задание

Легко

Давайте создадим систему автоматизации умного дома с использованием паттерна Command! Вы создадите систему, в которой различными домашними devices можно управлять с помощью команд, что позволяет ставить actions в очередь, выполнять их и даже сохранять для последующего использования — подобно универсальному пульту, которому не нужно знать, как работает каждое device внутри.

Вы организуете свой код в четырех файлах:

  • Command.java: Define Command interface, который будут Implement все команды devices. Он должен Declare один method execute(), выполняющий action команды.
  • Devices.java: Create два receiver класса, представляющих devices умного дома:

    Television — имеет methods powerOn(), который выводит TV is now ON, powerOff(), который выводит TV is now OFF, и setChannel(int channel), который выводит TV channel set to [channel].

    Thermostat — имеет methods setTemperature(int temp), который выводит Thermostat set to [temp] degrees, и turnOff(), который выводит Thermostat turned OFF.

  • Commands.java: Create Concrete command classes, которые encapsulate операции devices:

    TVOnCommand — принимает Television в своем constructor и вызывает powerOn() при выполнении.

    TVOffCommand — принимает Television в своем constructor и вызывает powerOff() при выполнении.

    TVChannelCommand — принимает Television и int channel в своем constructor и вызывает setChannel() с этим channel при выполнении.

    ThermostatSetCommand — принимает Thermostat и int temperature в своем constructor и вызывает setTemperature() с этим значением при выполнении.

  • Main.java: Create класс RemoteControl (invoker), у которого есть method setCommand(Command cmd) для сохранения команды и pressButton() для выполнения сохраненной команды.

    В своем main method вы получите два inputs: номер канала телевизора (целое число) и температуру термостата (целое число).

    Create Television и Thermostat. Create RemoteControl и Demonstrate паттерн Command следующим образом:

    1. Установить TVOnCommand и нажать button
    2. Установить TVChannelCommand с вашим input channel и нажать button
    3. Установить ThermostatSetCommand с вашей input temperature и нажать button
    4. Установить TVOffCommand и нажать button

Вы получите два inputs по порядку: channel телевизора (целое число) и temperature термостата (целое число).

Например, при inputs 5 и 72 ваш вывод будет таким:

TV is now ON
TV channel set to 5
Thermostat set to 72 degrees
TV is now OFF

Обратите внимание, что RemoteControl никогда напрямую не взаимодействует с devices. Он знает только об Command interface. Каждая команда encapsulate всё необходимое для выполнения своего action, благодаря чему легко добавлять новые devices и команды, не изменяя invoker!

Попробуйте сами

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. Set a ThermostatSetCommand with the input temperature and press the button
        // 4. Установите TVOffCommand и нажмите кнопку
        
        scanner.close();
    }
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование

Потренируйтесь самостоятельно: Онлайн-компилятор Java