Подтвердить что ты не робот

Почему я должен использовать шаблон проектирования команд, когда я могу легко вызвать требуемые методы?

Я изучаю шаблон дизайна , и я совершенно смущен тем, как его использовать. Пример, который у меня есть, связан с классом удаленного управления, который используется для включения и выключения подсветки.

Почему я не должен использовать методы switchOn()/switchOff() класса Light, а не отдельные классы и методы, которые в конечном итоге вызывают методы switchOn/switchOff?

Я знаю, что мой пример довольно прост, но в этом все дело. Я не мог найти сложной проблемы в любом месте в Интернете, чтобы увидеть точное использование шаблона проектирования команд.

Если вам известно о любой сложной проблеме реального мира, которую вы решили решить, используя этот шаблон дизайна, пожалуйста, поделитесь этим со мной. Это помогает мне и будущим читателям этого сообщения лучше понимать использование этого шаблона дизайна. Благодаря

//Command
public interface Command {
  public void execute();
}

//Concrete Command
public class LightOnCommand implements Command {

  //Reference to the light
  Light light;

  public LightOnCommand(Light light) {
    this.light = light;
  }

  public void execute() {
    light.switchOn();        //Explicit call of selected class method
  }
}

//Concrete Command
public class LightOffCommand implements Command {

  //Reference to the light
  Light light;

  public LightOffCommand(Light light) {
    this.light = light;
  }

  public void execute() {
    light.switchOff();
  }
}

//Receiver
public class Light {
  private boolean on;

  public void switchOn() {
    on = true;
  }

  public void switchOff() {
    on = false;
  }
}

//Invoker
public class RemoteControl {
  private Command command;

  public void setCommand(Command command) {
    this.command = command;
  }

  public void pressButton() {
    command.execute();
  }
}

//Client
public class Client {
  public static void main(String[] args) {
    RemoteControl control = new RemoteControl();
    Light light = new Light();
    Command lightsOn = new LightsOnCommand(light);
    Command lightsOff = new LightsOffCommand(light);

    //Switch on
    control.setCommand(lightsOn);
    control.pressButton();

    //Switch off
    control.setCommand(lightsOff);
    control.pressButton();
  }
}

Почему я не должен использовать код следующим образом?

 Light light = new Light();
 switch(light.command) {
  case 1:
    light.switchOn();
    break;
  case 2:
    light.switchOff();
    break;
 }
4b9b3361

Ответ 1

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

Это позволяет вам делать такие вещи, как список команд, которые выполняются по порядку, которые зависят от других элементов, которые назначены для какого-либо события запуска и т.д.

В вашем примере у вас могут быть другие классы (например, Air Conditioner), которые имеют свои собственные команды (например, Turn Thermostat Up, Turn Thermostat Down). Любые из этих команд могут быть назначены кнопке или активированы, когда выполняется какое-либо условие, не требуя какого-либо знания команды.

Итак, в итоге, шаблон инкапсулирует все, что требуется для принятия действия, и позволяет выполнять действие полностью независимо от любого из этого контекста. Если это не является требованием для вас, то шаблон, вероятно, не поможет вашему проблемному пространству.

Вот простой пример:

interface Command {
    void execute();
}

class Light {
    public Command turnOn();
    public Command turnOff();
}

class AirConditioner {
    public Command setThermostat(Temperature temperature);
}

class Button {
    public Button(String text, Command onPush);
}

class Scheduler {
    public void addScheduledCommand(Time timeToExecute, Command command);
}

Затем вы можете делать такие вещи, как:

new Button("Turn on light", light.turnOn());
scheduler.addScheduledCommand(new Time("15:12:07"), airCon.setThermostat(27));
scheduler.addScheduledCommand(new Time("15:13:02"), light.turnOff());

Как вы можете видеть, Button и Scheduler вообще ничего не должны знать о командах. Scheduler - пример класса, который может содержать набор команд.

Отметим также, что в Java 8 функциональные интерфейсы и ссылки на методы сделали этот тип кода еще более опрятным:

@FunctionalInterface
interface Command {
    void execute();
}

public Light {
    public void turnOn();
}

new Button("Turn On Light", light::turnOn);   

Теперь методы, которые превращаются в команды, даже не нужно знать о командах - если у них есть правильная подпись, вы можете спокойно создать анонимный командный объект, ссылаясь на метод.

Ответ 2

Давайте сосредоточимся на аспекте непроизводительности дизайна команды и некоторых основных причинах использования шаблона Command desing, сгруппированного по двум основным категориям:

  • Скрытие фактической реализации того, как выполняется команда
  • Разрешить создание методов вокруг команды, а также расширения команд

Скрыть реализацию

В большинстве программ вы хотите скрыть реализацию, чтобы при рассмотрении самой большой проблемы она состояла из понятного подмножества команд/кода. То есть Вам не нужно знать информацию о том, как включается свет, или автомобиль запускается. Если вы сосредоточены на том, чтобы запустить автомобиль, вам не нужно понимать, как работает двигатель, и как ему нужно топливо для входа в двигатель, как работают клапаны,...

Указание действия, а не как это делается

Команда дает вам такой вид. Вы сразу поймете, что делает команда TurnLightOn, или StartCar. Используя команду, вы скроете детали того, как это делается, четко указывая действие, которое должно быть выполнено.

Разрешить изменение внутренних деталей

Кроме того, скажем, вы позже перестройте весь класс Light или класс Car, который требует, чтобы вы создавали несколько разных объектов, и, возможно, вам нужно что-то еще, прежде чем выполнять свою желаемую операцию. В этом случае, если вы реализовали метод прямого доступа, во многих местах вам нужно будет изменить его во всех местах, где вы предварительно закодировали его. Используя команду, вы можете изменить внутренние детали того, как делать вещи, не изменяя вызов команды.

Возможные расширения команд

Использование интерфейса Command дает вам дополнительный уровень между кодом с помощью команды и кодом, выполняющим действительное действие команды. Это может привести к нескольким хорошим сценариям.

Расширение безопасности или воздействие интерфейса

Используя командный интерфейс, вы также можете ограничить доступ к своим объектам, что позволяет вам определить еще один уровень безопасности. Было бы разумно иметь модуль/библиотеку с достаточно открытым доступом, чтобы вы могли легко обрабатывать внутренние специальные случаи.

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

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

Общий интерфейс для выполнения файлов

При создании достаточной большой системы команды дают аккуратный способ соединения между различными модулями/библиотеками. Вместо того, чтобы проверять каждую деталь реализации любого класса, вы можете посмотреть, какие команды имеют доступ к классу.

И поскольку вы не учитываете детали реализации самой команды, вы можете использовать общий метод для создания экземпляра команды, выполнения ее и просмотра результата. Это позволяет упростить кодирование, вместо того, чтобы читать о том, как создать экземпляр этого конкретного класса Light или Car, и определить его результат.

Последовательность команд

Используя команды, вы также можете делать такие вещи, как последовательность команд. То есть, поскольку вы не выполняете команду TurnOnLight или StartCar, вы можете выполнять последовательности тезисов, так как они выполняются одинаково. Который по очереди позволяет запускать цепочки команд, которые могут быть полезны в нескольких ситуациях.

Вы можете создавать макросы, выполнять команды, которые, по вашему мнению, группируются вместе. То есть последовательность команд: UnlockDoor, EnterHouse, TurnOnLight. Естественная последовательность команд, но вряд ли может быть использована в методе, поскольку он использует разные объекты и действия.

Сериализация команд

Команды, довольно небольшие по своей природе, также позволяют сериализовать довольно хорошо. Это полезно в контексте сервера-клиента или в контексте программы-микросервиса.

Сервер (или программа) может запускать команду, которая затем сериализует команду, передает ее по некоторому протоколу связи (то есть очередь событий, очередь сообщений, http,...) кому-то, кто действительно обрабатывает эту команду. Нет необходимости сначала создавать экземпляр объекта на сервере, т.е. Light, который может быть легким (предназначенным для каламбура), или Car, который может быть действительно большой структурой. Вам просто нужна команда и, возможно, несколько параметров.

Это может быть хорошим местом для ознакомления с CQRS - схемой разделения ответственности за запрос команд для дальнейших исследований.

Отслеживание команд

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

Это позволяет легко изменять систему ведения журнала или добавлять такие вещи, как время, или включение/отключение ведения журнала. И все это легко поддерживается в командном модуле.

Отслеживание команд также позволяет разрешать отмену действий, поскольку вы можете выбрать повторную итерацию команд из заданного состояния. Требуется немного дополнительной настройки, но довольно легко выполнимо.


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

Ответ 3

Возможности много, но обычно это что-то вроде:

  • создание рамки командной строки, которая абстрагирует разбор параметров из действия. Затем вы можете зарегистрировать действие с чем-то вроде opts.register("--on", new LightOnCommand()).
  • позволяет пользователям перетаскивать последовательность действий для выполнения в виде макроса
  • регистрация обратного вызова при срабатывании какого-либо события, например on(Event.ENTER_ROOM, new LightOnCommand())

Общая схема здесь состоит в том, что у вас есть одна часть кода, ответственная за выяснение того, что нужно предпринять какое-то действие, не зная, что это за действие, а другая часть кода знает, как сделать действие, но не когда это сделать.

Например, в этом первом примере экземпляр opts знает, что когда он видит параметр командной строки --on, он должен включить свет. Но он это знает, не зная, что означает "включить свет". На самом деле, вполне возможно, что экземпляр opts пришел из сторонней библиотеки, поэтому он не может знать о фарах. Все, что он знает о том, как сопоставить действия (команды) с параметрами командной строки, которые он анализирует.

Ответ 4

Вам не обязательно. Шаблоны проектирования - это просто рекомендации, которые некоторые люди в прошлом нашли полезными при написании приложений значительной сложности.

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

Меньше кода почти всегда лучше, чем больше кода.

Ответ 5

Пример ICommand, который вы даете, довольно ограничен и используется только на языке программирования, который не имеет лямбда-выражений. Спринтер хорошо описывает это в своих ответах, показывающих использование командных заводов.

В большинстве случаев шаблон команды включает другие методы, например, CanRun и/или Undo. Они позволяют кнопке обновлять свое состояние включения на основе состояния команды или приложения для реализации стека отмены.

Как и большинство шаблонов проектирования, Command Pattern приходит в себя, когда вещи становятся немного сложнее. Это также хорошо известно, поэтому помогает сделать ваш код понятным для большинства программистов.

Ответ 6

Вы можете делать все, что думаете, но хорошо следовать шаблону usability manageability кода.

В реальной жизни Light будет интерфейсом. У вас разные реализации Light, например LEDLight, TubeLight

Если вы выполните конкретную команду через Inovker (RemoteControl), вам не нужно беспокоиться об изменениях в имени метода в Receiver. switchOn() in Light can be changed to switchOnDevice() in future. Но это не влияет на Invoker, так как ConcreteCommand (LightsOnCommand) внесет соответствующие изменения.

Предположим, что сценарий, в котором вы публикуете свои интерфейсы для одной службы (служба A) и реализации в других службах (служба B).

Теперь служба A не должна знать об изменениях в Receiver.

Invoker обеспечивает свободную связь между отправителем и получателем сообщения.

Посмотрите еще на несколько связанных вопросов SE:

Использование шаблона проектирования команд

Командный шаблон кажется излишне сложным (чего я не понимаю?)

Ответ 7

Есть несколько преимуществ шаблона Command, который я испытал. Но прежде всего, я хотел бы напомнить, что, как и все другие шаблоны, этот шаблон также повышает читаемость кода и обеспечивает общее понимание вашей (возможно) общей базы кода.

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

Во-вторых, поскольку у вас есть свои методы как объекты, вы можете хранить/ставить их в очередь для их выполнения позже. Или отменить их даже после того, как вы их выполнили. Вот где этот шаблон поможет вам реализовать "Отменить".

Наконец, шаблон команды также используется для развязки исполнения команд и самих команд. Он, как официант, не знает, как приготовить заказы, которые он получил. Ему все равно. Он не должен знать. Если он это узнает, он тоже будет работать поваром. И если владелец ресторана хочет уволить официанта, он/она заканчивает тем, что не имеет повара. Конечно, это определение не является особенным или связано только с шаблоном команды. Это объясняет, почему нам требуется разделение или управление зависимостями в целом.

Ответ 8

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

Command Pattern в основном инкапсулирует запрос как объект и тем самым позволяет параметризовать другие объекты с разными запросами и поддерживать отмененные операции.

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

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

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

Шаблон команды помогает нам развязать invoker (пульт дистанционного управления) и приемник (свет, вентилятор и т.д.) С помощью объекта команды (LightOnCommand, FanOffCommand и т.д.).