Skip to main content

🧩 Command Pattern

βœ… Intent​

  • Encapsulate a request as a command object
  • Useful for recording, re-executing, or scheduling operations

βœ… Motivation​

  • The processing logic is passed in from the outside β†’ execute()
  • Well-suited for Undo/Redo functionality or batch operations

βœ… When to Use​

  • When operation history matters, such as in user actions or batch processing
  • When operations need to be deferred or accumulated

βœ… Code Example​

// γ‚³γƒžγƒ³γƒ‰γ‚€γƒ³γ‚ΏγƒΌγƒ•γ‚§γƒΌγ‚Ή
interface DiscountCommand {
execute(basePrice: number): number;
}

// ε„γ‚³γƒžγƒ³γƒ‰οΌˆConcreteCommandοΌ‰
class StudentDiscountCommand implements DiscountCommand {
execute(basePrice: number): number {
return basePrice * 0.8;
}
}

class MemberDiscountCommand implements DiscountCommand {
execute(basePrice: number): number {
return basePrice * 0.9;
}
}

class VIPDiscountCommand implements DiscountCommand {
execute(basePrice: number): number {
return basePrice * 0.7;
}
}

class NoDiscountCommand implements DiscountCommand {
execute(basePrice: number): number {
return basePrice;
}
}

// Invoker
class DiscountExecutor {
constructor(private command: DiscountCommand) {}

setCommand(command: DiscountCommand) {
this.command = command;
}

run(basePrice: number): number {
return this.command.execute(basePrice);
}
}

// εˆ©η”¨δΎ‹
const userType = "member";
let command: DiscountCommand;

switch (userType) {
case "student":
command = new StudentDiscountCommand();
break;
case "member":
command = new MemberDiscountCommand();
break;
case "vip":
command = new VIPDiscountCommand();
break;
default:
command = new NoDiscountCommand();
}

const executor = new DiscountExecutor(command);
console.log(executor.run(1000)); // 900

βœ… Explanation​

This code applies the Command pattern to encapsulate discount logic as command objects that can be dynamically executed.
The Command pattern expresses operations as objects, enabling deferred execution, queuing, or undo capabilities.

1. Overview of the Command Pattern​

  • Command: Defines the interface for encapsulated operations

    • Represented by DiscountCommand in this code
  • ConcreteCommand: Implements the Command interface and provides specific logic

    • Implemented by StudentDiscountCommand, MemberDiscountCommand, VIPDiscountCommand, and NoDiscountCommand
  • Invoker: Executes the command

    • Represented by DiscountExecutor
  • Client: Creates the appropriate command and passes it to the invoker

    • Represented by the part of the code that uses a switch statement to generate a DiscountCommand and pass it to DiscountExecutor

2. Key Classes and Their Roles​

  • DiscountCommand

    • Common interface for discount operations
    • Declares the method execute(basePrice: number): number
  • StudentDiscountCommand, MemberDiscountCommand, VIPDiscountCommand, NoDiscountCommand

    • Concrete command classes implementing DiscountCommand
    • Each applies a different discount rate
  • DiscountExecutor

    • The Invoker class
    • Uses setCommand to receive a command, and run to execute it
  • Client

    • Generates the appropriate command using a switch statement based on user type and passes it to the DiscountExecutor

3. UML Class Diagram​

4. Benefits of the Command Pattern​

  • Encapsulation of Actions: Operations are expressed as objects, enabling deferred execution, queuing, and undo functionality
  • Flexibility: New commands can be added simply by implementing DiscountCommand
  • Generic Invoker: DiscountExecutor can execute any command, increasing its reusability

This design improves flexibility and extensibility by treating operations as first-class objects. It is particularly useful when dynamic switching or history management is required.