## Command Pattern
### Problem
Sometimes, object behavior contain complicated constraints. Sometimes, the system require the behavior to be invoked by an object but performed by another (this is common in presentation layer/domain layer separation in MVC enterprise systems). Sometimes, the system requires behavior to be undone. Sometimes the system requires a history of the behaviors that were being performed.

### Solution
These problems have a common solution, the **command pattern**. A `Command` is a more powerful version of a `Strategy`. While both of them encapsulates behavior, a `Strategy` is just that, a function wrapper. A `Command` on the other hand contains which object performs the behavior, which parameters are needed to perform the behavior, and how to undo the command (if needed).
Creating `Command`s, allow for more flexible behavior responsibility assignments. A separate `Invoker` object triggers the behavior by creating a command. This `Invoker` prepares the command with the appropriate `Reciever` (the object performing the command), and the appropriate parameters. The invoker then executes the prepared command. The command doesn't actually do anything, it just tells the `Reciever` to call the appropriate method.
This separation of responsibility allows for the creation of extra features that may be required for your system:
- If you want to keep a history of the performed commands, the `Invoker` may keep a list of `Commands`. This way the data stored in the list history, is a perfect representation of the previous commands.
- If you want the `Commands` to be undoable, you can store a backup of the receiver (and other affected objects) by the `Command` inside each instance of `Command` . Undoing a command will be as simple as restoring the receiver to its backup.

> Instead of passing the receiver in the `Invoker` methods, you can create an attribute called receiver inside `Invoker`. But doing this will make it so there is one `Receiver` instance for every `Invoker` instance.
>
> The commands should only affect the receiver. If the behavior that is performed changes a lot of objects, then make a `Receiver` class that encapsulates all of the affected objects. Doing this will make the implementation of undo easier since the backup inside of the command will simply be an older version of `Receiver`.
>
> Different command realizations are not necessarily of the same`Strategy`. That's why the parameters of the behavior are stored as attributes of the command, not passed in the `execute()` function. This is so that no matter what the command is, all `execute()` functions will have the same type signatures.
### General Example Without Undo
```python!
from abc import ABC,abstractmethod
class Command(ABC):
@abstractmethod
def execute(self):
pass
@abstractmethod
def __str__(self):
pass
class RealCommand1(Command):
def __init__(self,param,receiver):
self.__param = param
self.__receiver = receiver
def execute(self):
self.__receiver.performOperation1(self.__param)
def __str__(self):
return("Real Command 1 with params: %s received by %s" % (self.__param,self.__receiver))
class RealCommand2(Command):
def __init__(self,param,otherParam,receiver):
self.__param = param
self.__otherParam = otherParam
self.__receiver = receiver
def execute(self):
self.__receiver.performOperation2(self.__param,self.__otherParam)
def __str__(self):
return("Real Command 2 with params: %s and %s received by %s" % (self.__param,self.__otherParam,self.__receiver))
class Receiver:
def __init__(self,someAttribute:str):
self.__someAttribute = someAttribute
def performOperation1(self,param):
self.__someAttribute += "attribute now changed, "
print("operation1 executed with %s" % param)
def performOperation2(self,param,otherParam):
self.__someAttribute += "this attribute is new, "
print("operation2 executed with %s and %s" % (param,otherParam))
def someAttribute(self) -> str:
return self.__someAttribute
class Invoker:
def invokeCommand1(self,param,receiver):
c = RealCommand1(param,receiver)
command = c
print(c)
command.execute()
def invokeCommand2(self,param,otherParam,receiver):
command = RealCommand2(param,otherParam,receiver)
command.execute()
r = Receiver("this ")
r2 = Receiver("that ")
i = Invoker()
i.invokeCommand1("foo",r)
print(r.someAttribute())
print()
i.invokeCommand2("foo","bar",r)
print(r.someAttribute())
print()
i.invokeCommand1("foo",r2)
print(r2.someAttribute())
print(r.someAttribute())
```
### General Example With Undo
```python!
from abc import ABC,abstractmethod
class Command(ABC):
@abstractmethod
def execute(self):
pass
@abstractmethod
def __str__(self):
pass
@abstractmethod
def undo(self):
pass
class RealCommand1(Command):
def __init__(self,param,receiver):
self.__param = param
self.__receiver = receiver
self.__backup = receiver.copy()
def execute(self):
self.__receiver.performOperation1(self.__param)
def undo(self):
self.__receiver.restore(self.__backup)
def __str__(self):
return("Real Command 1 with params: %s received by %s" % (self.__param,self.__receiver))
class RealCommand2(Command):
def __init__(self,param,otherParam,receiver):
self.__param = param
self.__otherParam = otherParam
self.__receiver = receiver
self.__backup = receiver.copy()
def execute(self):
self.__receiver.performOperation2(self.__param,self.__otherParam)
def undo(self):
self.__receiver.restore(self.__backup)
def __str__(self):
return("Real Command 2 with params: %s and %s received by %s" % (self.__param,self.__otherParam,self.__receiver))
class Receiver:
def __init__(self,someAttribute:str):
self.__someAttribute = someAttribute
def performOperation1(self,param):
self.__someAttribute += "attribute now changed, "
print("operation1 executed with %s" % param)
def performOperation2(self,param,otherParam):
self.__someAttribute += "this attribute is new, "
print("operation2 executed with %s and %s" % (param,otherParam))
def someAttribute(self) -> str:
return self.__someAttribute
def restore(self,backup):
self.__someAttribute = backup.someAttribute()
def copy(self) -> 'Receiver':
return Receiver(self.__someAttribute)
class Invoker:
def __init__(self):
self.__commandHistory = []
def displayHistory(self):
for command in self.__commandHistory:
print(command)
def invokeCommand1(self,param,receiver):
command = RealCommand1(param,receiver)
command.execute()
self.__commandHistory.append(command)
def invokeCommand2(self,param,otherParam,receiver):
command = RealCommand2(param,otherParam,receiver)
command.execute()
self.__commandHistory.append(command)
def undoPreviousCommand(self):
undoneCommand = self.__commandHistory.pop()
undoneCommand.undo()
r = Receiver("this")
i = Invoker()
i.invokeCommand1("foo",r)
print(r.someAttribute())
i.invokeCommand2("foo","bar",r)
print(r.someAttribute())
i.displayHistory()
i.undoPreviousCommand()
print(r.someAttribute())
i.undoPreviousCommand()
print(r.someAttribute())
```