Привет всем, Форумчане!
Разобрался-таки основательно(как мне кажется) с паттером
Command
и хочу попытаться рассказать о нем "своими словами".
![Паттерн Command своими словами - 1]()
Исходя из Википедии, можем узнать, что цель его — это
создание структуры, в которой класс-отправитель и класс-получатель не зависят друг от друга напрямую. Организация обратного вызова к классу, который включает в себя класс-отправитель.
В принципе написано чётко и правильно, но это в теории. А как же сделать это? Вот этим начинаются проблемы, т.к. описание уже не так ясно и очевидно. Поэтому я как разобрался, решил рассказать вам как я это понял, может кому-то и пригодится:
Исходя из описания цели этого паттерна, буду комбинировать описание сразу с кодом, чтоб было нагляднее, т.к. в той же википедии обобщили для многих языков и поэтому описание отделено от примера.
В этом паттерне есть четыре термина, пока примем их как данность: команды(
command
), приемник команд(
receiver
), вызывающий команды(
invoker
) и клиент(
client
).
Пример буду брать с той же Википедии, он вполне сносный.
Задача
есть класс
Light
, который умеет две вещи: включить свет и выключить. Он в терминах паттерна будет "приемник команд (
receiver
)"
/*Receiver class*/
public class Light{
public Light(){ }
public void turnOn(){
System.out.println("The light is on");
}
public void turnOff(){
System.out.println("The light is off");
}
}
Создадим интерфейс с одним методом
execute()
, который будет выполнять и который называется в терминах паттерна "команда (
command
)"
/*the Command interface*/
public interface Command{
void execute();
}
Необходимо инкапсулировать выполнение умений класса
Light
. Для этого мы создадим классы
TurnOnLightCommand
и
TurnOffLightCommand
, которые реализуют интерфейс
Command
и которые будут принимать в конструкторе объект класса
Light
. И каждый из них будет выполнять только одно действие. Один будет вызывать метод
turnOn()
, а другой
turnOff()
.
/*the Command for turning on the light*/
public class TurnOnLightCommand implements Command{
private Light theLight;
public TurnOnLightCommand(Light light){
this.theLight=light;
}
public void execute(){
theLight.turnOn();
}
}
/*the Command for turning off the light*/
public class TurnOffLightCommand implements Command{
private Light theLight;
public TurnOffLightCommand(Light light){
this.theLight=light;
}
public void execute(){
theLight.turnOff();
}
}
Теперь пришло время создать объект, который бы принимал эти инкапсулированные методы объекта
Light
. Он в терминах паттерна называется вызывающий команды (invoker). Назовем его
Switch
и пусть он будет принимать в конструкторе переменные
Command
, которые будут использоваться в созданных методах
flipUp()
и
flipDown()
.
/*the Invoker class*/
public class Switch {
private Command flipUpCommand;
private Command flipDownCommand;
public Switch(Command flipUpCommand,Command flipDownCommand){
this.flipUpCommand=flipUpCommand;
this.flipDownCommand=flipDownCommand;
}
public void flipUp(){
flipUpCommand.execute();
}
public void flipDown(){
flipDownCommand.execute();
}
}
Ну и конечно создадим класс который будет использовать их, чтобы понять что происходит вообще. Он будет именть метод main, в котором и будет происходить всё действие:
/*The test class*/
public class TestCommand{
public static void main(String[] args){
// создаем объект, который будет использоваться
Light l=new Light();
// создаем объекты для всех умений объекта Light:
Command switchUp=new TurnOnLightCommand(l);
Command switchDown=new TurnOffLightCommand(l);
// Создаемтся invoker, с которым мы будем непосредственно контактировать:
Switch s=new Switch(switchUp,switchDown);
// вот проверка этого, используем методы:
s.flipUp();
s.flipDown();
}
}
На выводе будет следующее:
"The light is on"
"The light is off"
Где это применяется?
По цели ясно, что и для чего это нужно, а именно: в ситуации, когда нужно отделить конкретное исполнение, это очень удобно. Чтоб использование каких-то функций не зависело от конкретной реализации и ее можно было изменять без ущерба для системы.
как-то так...)
Пишите свои комментарии, давайте обсуждать, может что-то можно сделать проще и рассказать лучше, будем всё править, если необходимо) Чтоб для тех, кто будет читать первый раз, было как можно понятнее.
Ну и кому понравится статья — ставьет "+" на ней :) Для меня это важно)
Со временем хочу написать еще про
Builder
,
Singleton
и прочие.
См. также мои другие статьи:
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
насколько я понял этот паттерн у тебя еще должен быть CommandExecutor(единственная точка входа)
то есть к самим командам у тебя не должен быть доступа.
соот-но команды ты должен вызывать CommandExecutor.execute(Команда)