策略模式

策略模式

策略是一种行为设计模式, 它将一组行为转换为对象, 并使其在原始上下文对象内部能够相互替换。原始对象被称为上下文, 它包含指向策略对象的引用并将执行行为的任务分派给策略对象。 为了改变上下文完成其工作的方式, 其他对象可以使用另一个对象来替换当前链接的策略对象。

应用场景

一天, 你打算为游客们创建一款导游程序。 该程序的核心功能是提供美观的地图, 以帮助用户在任何城市中快速定位。用户期待的程序新功能是自动路线规划:他们希望输入地址后就能在地图上看到前往目的地的最快路线。程序的首个版本只能规划公路路线。驾车旅行的人们对此非常满意。 但很显然, 并非所有人都会在度假时开车。 因此你在下次更新时添加了规划步行路线的功能。 此后, 你又添加了规划公共交通路线的功能。而这只是个开始。 不久后, 你又要为骑行者规划路线。又过了一段时间, 你又要为游览城市中的所有景点规划路线。尽管从商业角度来看, 这款应用非常成功, 但其技术部分却让你非常头疼: 每次添加新的路线规划算法后,导游应用中主要类的体积就会增加一倍。 终于在某个时候, 你觉得自己没法继续维护这堆代码了。

解决方案

策略模式建议找出负责用许多不同方式完成特定任务的类, 然后将其中的算法抽取到一组被称为策略的独立类中。

alt text

在导游应用中, 每个路线规划算法都可被抽取到只有一个 build­Route生成路线方法的独立类中。 该方法接收起点和终点作为参数, 并返回路线中途点的集合。

结构图

alt text

示例代码


class Strategy
{
public:
  virtual ~Strategy() {}
  virtual std::string doAlgorithm(const std::vector<std::string>&data)const = 0;
};

/* The context defines the interface of interest to clients*/
class Context
{
private:
  Strategy * stragety_;

public:
  Context(Strategy *strategy = nullptr) : strategy_(strategy)
   {
   }
   ~Context()
   {
       delete this->strategy_;
   }
   /**
    * Usually, the Context allows replacing a Strategy object at runtime.
    */
   void set_strategy(Strategy *strategy)
   {
       delete this->strategy_;
       this->strategy_ = strategy;
   }
   /**
    * The Context delegates some work to the Strategy object instead of
    * implementing +multiple versions of the algorithm on its own.
    */
   void DoSomeBusinessLogic() const
   {
       // ...
       std::cout << "Context: Sorting data using the strategy (not sure how it'll do it)\n";
       std::string result = this->strategy_->DoAlgorithm(std::vector<std::string>{"a", "e", "c", "b", "d"});
       std::cout << result << "\n";
       // ...
   }
};

class ConcreteStrategyA : public Strategy
{
public:
    std::string DoAlgorithm(const std::vector<std::string> &data) const override
    {
        std::string result;
        std::for_each(std::begin(data), std::end(data), [&result](const std::string &letter) {
            result += letter;
        });
        std::sort(std::begin(result), std::end(result));

        return result;
    }
};
class ConcreteStrategyB : public Strategy
{
    std::string DoAlgorithm(const std::vector<std::string> &data) const override
    {
        std::string result;
        std::for_each(std::begin(data), std::end(data), [&result](const std::string &letter) {
            result += letter;
        });
        std::sort(std::begin(result), std::end(result));
        for (int i = 0; i < result.size() / 2; i++)
        {
            std::swap(result[i], result[result.size() - i - 1]);
        }

        return result;
    }
};

int main()
{
  Context *context = new Context(new ConcreteStrategyA);
  std::cout << "Client: Strategy is set to normal sorting.\n";
  context->DoSomeBusinessLogic();
  std::cout << "\n";
  std::cout << "Client: Strategy is set to reverse sorting.\n";
  context->set_strategy(new ConcreteStrategyB);
  context->DoSomeBusinessLogic();
  delete context;
  return 0;
}

与其他模式关系

  • 命令模式 和策略看上去很像, 因为两者都能通过某些行为来参数化对象。 但是它们的意图有非常大的不同。
    1.

posted on 2021-05-24 15:28  Ultraman_X  阅读(40)  评论(0编辑  收藏  举报

导航