Skip to content
  • 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

    1. Declare command interface with a single execute method.
    2. 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.)
    3. Sender objects only interact with commands using the command interface.
    4. 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
  • 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 a map[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
  • Edited by Prince of Devils
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment