2023年3月2日 星期四

C++:介紹 Command Pattern 以及與 Strategy Pattern 的比較

本文為 C++ Software Design 書的第 21 節內容。

Command Pattern 的目的是將一個動作封裝起來,並且支援取消此動作的功能。以下為一個計算機的例子:

// Interface
class CalculatorCommand
{
public:
  virtual int execute(int i) const = 0;
  virtual int undo(int i) const = 0;
};

class Add : public CalculatorCommand
{
public:
  explicit Add (int operand) : operand_{operand} {}
  int execute(int i) const override { return i + operand_; }
  int undo(int i) const override { return i - operand_; }
private:
  int operand_{};
};
class Subtract : public CalculatorCommand
{
public:
  explicit Subtract (int operand) : operand_{operand} {}
  int execute(int i) const override { return i - operand_; }
  int undo(int i) const override { return i + operand_; }
private:
  int operand_{};
};

class Calculator
{
public:
  void compute(std::unique_ptr<CalculatorCommand> command)
  {
    current_ = command->execute(current_);
    stack_.push(std::move(command));
  }
  void undoLast ()
  {
    if (stack_.empty()) return;
    auto command = std::move(stack_.top());
    stack_.pop();
    current_ = command->undo(current_);
  }
private:
  int current_{};
  std::stack<std::unique_ptr<CalculatorCommand>> stack_;
};
可以看出 Calculator class 支援 CalculatorCommand 介面,並且也能 undo。

Command Pattern 與 Strategy Pattern 最大的差別是在設計時想要的是 what 還是 how。也就是說 Command Pattern 的概念是直接去做想要的動作,而 Strategy Pattern 則是定下了如何做這個動作的規則。

如果將計算機的例子寫成 Strategy Pattern 的話會像以下例子:

class CalculatorStrategy
{
public:
  virtual int compute(int i) const = 0;
};

class Calculator
{
public:
  void set(std::unique_ptr<CalculatorStrategy> op) { op_ = op; }
  void compute(int val) { current_ = op_->compute(val); }
private:
  int current_;
  std::unique_ptr<CalculatorStrategy> op_;
}
可以看出 Strategy Pattern 必須先 set 再 compute,而 Command Pattern 就直接計算結果了。

沒有留言:

張貼留言