-
Command is a behavioral design pattern that turns a request into a stand-alone object that contains all information about the request. This transformation lets you pass requests as a method arguments, delay or queue a request’s execution, and support undoable operations.
-- https://refactoring.guru/design-patterns/command- Declare command interface with a single
execute
method. - Extract requests into concrete commands. Each command needs fields for storing the request arguments. A command also needs a reference to the actual receiver. (Usually, all these values are initialized with the constructor.)
- Sender objects only interact with commands using the command interface.
- Client initializes objects:
- create receivers
- create commands and associate them with receivers
- create senders and associate them with specific commands
Edited by Prince of Devils - Declare command interface with a single
-
Pros:
- Classes that invoke operations are decoupled from classes that perform these operations
- Deferred execution: commands can be serialized and stored, or sent over the network to be executed by a different machine
- A set of simple commands can be assembled together into a complex one
- Makes things like GUI Buttons, Macro recording, Undo/Redo simpler
-
Problem: The parameters to a command need to be passed to it right when it is created (its constructor or #LC9-11). But what if we don't know the parameters at that point in time yet?
Solution 1: Instead of passing the parameters directly to the command, make it accept an interface that will then get them dynamically. Depending on the programming language, also a method reference that points to a method returning the desired information could be used.func main() { // ... saveUserCMD.ui := &UserInfoGetter{} // ... } type interface UserInfo { GetName() string GetPassword() string } type UserInfoGetter struct{} func (u *UserInfoGetter) GetName() { /* ... */ } func (u *UserInfoGetter) GetPassword() { / ... */ } type SaveUserCommand struct { db store.User // Parameters ui UserInfo } func (sc *SaveUserCommand) Execute() { sc.db.RequestCreate(sc.ui.GetName(), sc.ui.GetPassword()) }
Solution 2: Use a context object. Context could be something like a Dictionary<String, object>, or in Go rather amap[string]interface{}
.type interface Command { Execute(Context) }
Both terrible solutions, (1) because we break our loose coupling, and (2), if we ever end up with a
map[string]interface{}
we really should re-think all our life choices. (Except you're trying to parse to ld+json :').)Solution 3:
In our example with button presses, another design pattern may be better suited:
- Chain of Responsibility
- Mediator
Edited by Prince of Devils
Please register or sign in to comment