Команда (шаблон проектирования) | это... Что такое Команда (шаблон проектирования)? (original) (raw)
У этого термина существуют и другие значения, см. Команда.
Шаблон проектирования
Команда | |
---|---|
Command | |
Тип: | поведенческий |
Назначение: | для обработки команды в виде объекта |
Родственные шаблоны: | Компоновщик, Хранитель, Прототип, Одиночка |
Описан в Design Patterns | Да |
Команда — шаблон проектирования, используемый при объектно-ориентированном программировании, представляющий действие. Объект команды заключает в себе само действие и его параметры.
Содержание
Цель
Создание структуры, в которой класс-отправитель и класс-получатель не зависят друг от друга напрямую. Организация обратного вызова к классу, который включает в себя класс-отправитель.
Описание
Паттерн поведения объектов,известен так же под именем Action(действие).
Обеспечивает обработку команды в виде объекта, что позволяет сохранять её, передавать в качестве параметра методам, а также возвращать её в виде результата, как и любой другой объект.
Например, библиотека печати может иметь класс PrintJob. Для его использования можно создать объект PrintJob, установить необходимые параметры, и вызвать метод, непосредственно отсылающий задание на печать.
Примеры
Пример на С++
Исходный текст на языке C++
class Document { vector data; public: void Insert( int line, const string & str ) { if ( !( line>data.size() ) ) data.insert( data.begin() + line, str ); else cout << "Error!" << endl; }
void Remove( int line )
{
if( !( line>data.size() ) )
data.erase( data.begin() + line );
else
cout << "Error!" << endl;
}
string & operator [] ( int x )
{
return data[x];
}
void Show()
{
for( int i = 0; i<data.size(); ++i )
{
cout << i + 1 << ". " << data[i] << endl; }
}
};
class Command { protected: Document * doc; public: virtual void Execute() = 0; virtual void unExecute() = 0;
void setDocument( Document * _doc )
{
doc = _doc;
}
};
class InsertCommand : public Command { int line; string str; public: InsertCommand( int _line, const string & _str ): line( _line ), str( _str ) {}
void Execute()
{
doc->Insert( line, str );
}
void unExecute()
{
doc->Remove( line );
}
};
class Reciver { vector<Command*> DoneCommands; Document doc; Command* command; public: void Insert( int line, string str ) { command = new InsertCommand( line, str ); command->setDocument( &doc ); command->Execute(); DoneCommands.push_back( command ); }
void Undo()
{
if( DoneCommands.size() == 0 )
{
cout << "There is nothing to undo!" << endl;
}
else
{
command = DoneCommands.back();
DoneCommands.pop_back();
command->unExecute();
}
}
void Show()
{
doc.Show();
}
};
int main() { char s = '1'; int line, line_b; string str; Reciver res; while( s!= 'e' ) { cout << "What to do: \n1.Add a line\n2.Undo last command" << endl; cin >> s; switch( s ) { case '1': cout << "What line to insert: "; cin >> line; --line; cout << "What to insert: "; cin >> str; res.Insert( line, str ); break; case '2': res.Undo(); break; } cout << "$$$DOCUMENT$$$" << endl; res.Show(); cout << "$$$DOCUMENT$$$" << endl; } return 0; }
Пример на С#
Исходный текст на языке C#
using System; using System.Collections.Generic;
namespace Command {
class MainApp { static void Main() { // Создаем пользователя. User user = new User();
// Пусть он что-нибудь сделает.
user.Compute('+', 100);
user.Compute('-', 50);
user.Compute('*', 10);
user.Compute('/', 2);
// Отменяем 4 команды
user.Undo(4);
// Вернём 3 отменённые команды.
user.Redo(3);
// Ждем ввода пользователя и завершаемся.
Console.Read();
}
}
// "Command" : абстрактная Команда
abstract class Command { public abstract void Execute(); public abstract void UnExecute(); }
// "ConcreteCommand" : конкретная команда
class CalculatorCommand : Command { char @operator; int operand; Calculator calculator;
// Constructor
public CalculatorCommand(Calculator calculator,
char @operator, int operand)
{
this.calculator = calculator;
this.@operator = @operator;
this.operand = operand;
}
public char Operator
{
set{ @operator = value; }
}
public int Operand
{
set{ operand = value; }
}
public override void Execute()
{
calculator.Operation(@operator, operand);
}
public override void UnExecute()
{
calculator.Operation(Undo(@operator), operand);
}
// Private helper function : приватные вспомогательные функции
private char Undo(char @operator)
{
char undo;
switch(@operator)
{
case '+': undo = '-'; break;
case '-': undo = '+'; break;
case '*': undo = '/'; break;
case '/': undo = '*'; break;
default : undo = ' '; break;
}
return undo;
}
}
// "Receiver" : получатель
class Calculator { private int curr = 0;
public void Operation(char @operator, int operand)
{
switch(@operator)
{
case '+': curr += operand; break;
case '-': curr -= operand; break;
case '*': curr *= operand; break;
case '/': curr /= operand; break;
}
Console.WriteLine(
"Current value = {0,3} (following {1} {2})",
curr, @operator, operand);
}
}
// "Invoker" : вызывающий
class User { // Initializers private Calculator _calculator = new Calculator(); private List _commands = new List();
private int _current = 0;
public void Redo(int levels)
{
Console.WriteLine("\n---- Redo {0} levels ", levels);
// Делаем возврат операций
for (int i = 0; i < levels; i++)
if (_current < _commands.Count - 1)
_commands[_current++].Execute();
}
public void Undo(int levels)
{
Console.WriteLine("\n---- Undo {0} levels ", levels);
// Делаем отмену операций
for (int i = 0; i < levels; i++)
if (_current > 0)
_commands[--_current].UnExecute();
}
public void Compute(char @operator, int operand)
{
// Создаем команду операции и выполняем её
Command command = new CalculatorCommand(
_calculator, @operator, operand);
command.Execute();
// Добавляем операцию к списку отмены
_commands.Add(command);
_current++;
}
} }
Пример на Java
Исходный текст на языке Java
/the Invoker class/
public class Switch { private Command flipUpCommand; private Command flipDownCommand;
public Switch(Command flipUpCmd,Command flipDownCmd){
this.flipUpCommand=flipUpCmd;
this.flipDownCommand=flipDownCmd;
}
public void flipUp(){
flipUpCommand.execute();
}
public void flipDown(){
flipDownCommand.execute();
}
}
/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");
}
}
/the Command interface/
public interface Command{ void execute(); }
/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(); } }
/The test class/ public class TestCommand{ public static void main(String[] args){ Light l=new Light(); Command switchUp=new TurnOnLightCommand(l); Command switchDown=new TurnOffLightCommand(l);
Switch s=new Switch(switchUp,switchDown);
s.flipUp();
s.flipDown();
} }
Пример JavaScript
Исходный текст на языке JavaScript
// Command: абстрактная Команда function Command() { this.execute = function() {}; this.unExecute = function() {}; }
// ConcreteCommand: конкретная команда function CalculatorCommand() { var calculator; var operator; var operand;
this.execute = function(newCalculator, newOperator, newOperand) {
// установка параметров команды
if (typeof(newCalculator)=="object" && typeof(newOperator)=="string" && typeof(newOperand)=="number") {
calculator = newCalculator;
operator = newOperator;
operand = newOperand;
}
// исполнение команды
calculator.operation(operator, operand);
};
this.unExecute = function() {
// исполнение обратной команды
calculator.operation(undo(operator), operand);
};
function undo(operator) {
// функция вернёт оператор, обратный переданному
// при желании, можно воспользоваться замыканием и не передавать оператор
switch(operator) {
case '+': return '-'; break;
case '-': return '+'; break;
}
return ' '; // результат по умолчанию
}
} CalculatorCommand.prototype = new Command(); CalculatorCommand.prototype.constructor = CalculatorCommand;
// Receiver: получатель function Calculator() { var val = 0;
this.operation = function(operator, operand) {
// производим операцию
switch(operator) {
case '+':
val += operand;
debug(operator, operand);
break;
case '-':
val -= operand;
debug(operator, operand);
break;
default:
alert("Неизвестный оператор");
break;
}
};
function debug(operator, operand) {
alert("Текущее значение: "+ val +"\nОперация: "+ operator + operand);
}
}
// Invoker: вызывающий function User() { var calculator = new Calculator(); var commands = []; // массив команд current = 0; // номер текущей команды
this.compute = function(operator, operand) {
var newCommand = new CalculatorCommand();
if (current<commands.length-1) {
// если "внутри undo" мы запускаем новую операцию,
// надо обрубать список команд, следующих после текущей,
// иначе undo/redo будут некорректны
commands.splice(current);
}
newCommand.execute(calculator, operator, operand);
commands.push(newCommand);
current++;
};
this.undo = function(levels) {
alert("отмена ("+ levels +")");
for (i=0; i<levels; i++) {
if (current > 0) {
commands[--current].unExecute();
}
}
};
this.redo = function(levels) {
alert("возврат ("+ levels +")");
for (i=0; i<levels; i++) {
if (current < commands.length) {
commands[current++].execute();
}
}
};
}
// использование var u = new User(); u.compute("+", 2); // 2, "+2" u.compute("+", 3); // 5, "+3" u.compute("-", 1); // 4, "-1" u.compute("+", 6); // 10, "+6" u.undo(3); // 4, "-6" // 5, "+1" // 2, "-3" u.redo(2); // 5, "+3" // 4, "-1" u.undo(2); // 5, "+1" // 2, "-3" u.compute("+", 8); // 10, "+8" u.undo(1); // 2, "-8" u.redo(2); // 10, "+8" // превышение длинны commands u.compute("+", 9); // 19, "+9"
Пример на PHP5
Исходный текст на языке PHP5
this−>calculator=this->calculator = this−>calculator=calculator; this−>operator=this->operator = this−>operator=operator; this−>operand=this->operand = this−>operand=operand; } /** * Переопределенная функция parent::Execute() */ public function Execute() { this−>calculator−>Operation(this->calculator->Operation(this−>calculator−>Operation(this->operator, $this->operand); } /** * Переопределенная функция parent::UnExecute() */ public function UnExecute() { this−>calculator−>Operation(this->calculator->Operation(this−>calculator−>Operation(this->Undo($this->operator), $this->operand); } /** * Какое действие нужно отменить? * * @private * @param string $operator * @return string */ private function Undo($operator) { //каждому произведенному действию найти обратное switch($operator) { case '+': $undo = '-'; break; case '-': $undo = '+'; break; case '*': $undo = '/'; break; case '/': $undo = '*'; break; default : $undo = ' '; break; } return $undo; } } /** * Класс получатель и исполнитель "команд" */ class Calculator { /** * Текущий результат выполнения команд * * @private * @var int */ private $curr = 0; public function Operation($operator,$operand) { //выбрать оператора для вычисления результата switch($operator) { case '+': this−>curr+=this->curr+=this−>curr+=operand; break; case '-': this−>curr−=this->curr-=this−>curr−=operand; break; case '*': this−>curr∗=this->curr*=this−>curr∗=operand; break; case '/': this−>curr/=this->curr/=this−>curr/=operand; break; } print("Текущий результат = this−>curr(послевыполненияthis->curr (после выполнения this−>curr(послевыполненияoperator c $operand)"); } } /** * Класс, вызывающий команды */ class User { /** * Этот класс будет получать команды на исполнение * * @private * @var object of class Calculator */ private $calculator; /** * Массив операций * * @private * @var array */ private $commands = array(); /** * Текущая команда в массиве операций * * @private * @var int */ private $current = 0; public function __construct() { //создать экземпляр класса, который будет исполнять команды $this->calculator = new Calculator(); } /** * Функция возврата отмененных команд * * @param int $levels количество возвращаемых операций */ public function Redo($levels) { print("\n---- Повторить $levels операций "); // Делаем возврат операций for ($i = 0; i<i < i<levels; $i++) if ($this->current < count($this->commands) - 1) this−>commands[this->commands[this−>commands[this->current++]->Execute(); } /** * Функция отмены команд * * @param int $levels количество отменяемых операций */ public function Undo($levels) { print("\n---- Отменить $levels операций "); // Делаем отмену операций for ($i = 0; i<i < i<levels; $i++) if ($this->current > 0) this−>commands[this->commands[this−>commands[this->current]->UnExecute(); } /** * Функция выполнения команд * * @param string $operator * @param mixed $operand */ public function Compute($operator, $operand) { // Создаем команду операции и выполняем её this−>command=newCalculatorCommand(this->command = new CalculatorCommand(this−>command=newCalculatorCommand(this->calculator, operator,operator, operator,operand); $this->command->Execute(); // Добавляем операцию к массиву операций и увеличиваем счетчик текущей операции this−>commands[]=this->commands[]=this−>commands[]=this->command; $this->current++; } } $user = new User(); // Произвольные команды $user->Compute('+', 100); $user->Compute('-', 50); $user->Compute('*', 10); $user->Compute('/', 2); // Отменяем 4 команды $user->Undo(4); // Вернём 3 отменённые команды. $user->Redo(3); ?>Пример на VB.NET
Исходный текст на языке VB.NET
Imports System.Collections.Generic
Namespace Command
Class Program
Shared Sub Main()
' Создаем пользователя.
Dim user As New User()
' Пусть он что-нибудь сделает.
user.Compute("+"c, 100)
user.Compute("-"c, 50)
user.Compute("*"c, 10)
user.Compute("/"c, 2)
' Отменяем 4 команды
user.Undo(4)
' Вернём 3 отменённые команды.
user.Redo(3)
' Ждем ввода пользователя и завершаемся.
Console.Read()
End Sub
End Class
' "Command" : абстрактная Команда
MustInherit Class Command
Public MustOverride Sub Execute()
Public MustOverride Sub UnExecute()
End Class
' "ConcreteCommand" : конкретная команда
Class CalculatorCommand
Inherits Command
Private m_operator As Char
Private m_operand As Integer
Private calculator As Calculator
' Constructor
Public Sub New(ByVal calculator As Calculator, ByVal [operator] As Char, ByVal operand As Integer)
Me.calculator = calculator
Me.m_operator = [operator]
Me.m_operand = operand
End Sub
Public WriteOnly Property [Operator]() As Char
Set(ByVal value As Char)
m_operator = value
End Set
End Property
Public WriteOnly Property Operand() As Integer
Set(ByVal value As Integer)
m_operand = value
End Set
End Property
Public Overrides Sub Execute()
calculator.Operation(m_operator, m_operand)
End Sub
Public Overrides Sub UnExecute()
calculator.Operation(Undo(m_operator), m_operand)
End Sub
' Private helper function : приватные вспомогательные функции
Private Function Undo(ByVal [operator] As Char) As Char
Dim undo__1 As Char
Select Case [operator]
Case "+"c
undo__1 = "-"c
Exit Select
Case "-"c
undo__1 = "+"c
Exit Select
Case "*"c
undo__1 = "/"c
Exit Select
Case "/"c
undo__1 = "*"c
Exit Select
Case Else
undo__1 = " "c
Exit Select
End Select
Return undo__1
End Function
End Class
' "Receiver" : получатель
Class Calculator
Private curr As Integer = 0
Public Sub Operation(ByVal [operator] As Char, ByVal operand As Integer)
Select Case [operator]
Case "+"c
curr += operand
Exit Select
Case "-"c
curr -= operand
Exit Select
Case "*"c
curr *= operand
Exit Select
Case "/"c
curr /= operand
Exit Select
End Select
Console.WriteLine("Current value = {0,3} (following {1} {2})", curr, [operator], operand)
End Sub
End Class
' "Invoker" : вызывающий
Class User
' Initializers
Private calculator As New Calculator()
Private commands As New List(Of Command)()
Private current As Integer = 0
Public Sub Redo(ByVal levels As Integer)
Console.WriteLine(vbLf & "---- Redo {0} levels ", levels)
' Делаем возврат операций
For i As Integer = 0 To levels - 1
If current < commands.Count - 1 Then
commands(System.Math.Max(System.Threading.Interlocked.Increment(current), current - 1)).Execute()
End If
Next
End Sub
Public Sub Undo(ByVal levels As Integer)
Console.WriteLine(vbLf & "---- Undo {0} levels ", levels)
' Делаем отмену операций
For i As Integer = 0 To levels - 1
If current > 0 Then
commands(System.Threading.Interlocked.Decrement(current)).UnExecute()
End If
Next
End Sub
Public Sub Compute(ByVal [operator] As Char, ByVal operand As Integer)
' Создаем команду операции и выполняем её
Dim command As Command = New CalculatorCommand(calculator, [operator], operand)
command.Execute()
' Добавляем операцию к списку отмены
commands.Add(command)
current += 1
End Sub
End Class
End Namespace
Ссылки
- Паттерн проектирования Command (Команда) — назначение, описание, реализация на С++, достоинства и недостатки
Шаблоны проектирования | |
---|---|
Основные | Делегирования • Интерфейс • Неизменяемый объект • Функционального дизайна |
Порождающие | Абстрактная фабрика • Объектный пул • Одиночка • Отложенная инициализация • Прототип • Строитель • Фабричный метод |
Структурные | Адаптер • Выделение частного класса данных • Декоратор • Заместитель • Компоновщик • Мост • Приспособленец • Фасад |
Поведенческие | Интерпретатор • Итератор • Команда • Наблюдатель • Посетитель • Посредник • Состояние • Стратегия • Хранитель • Цепочка обязанностей • Шаблонный метод |
Блокировка с двойной проверкой • Однопоточное выполнение • Планировщик |