设计模式【14】——策略模式( Strategy 模式)


前言

Strategy 模式和 Template 模式要解决的问题是相同的,都是为了给业务逻辑具体实现和抽象接口之间的解耦。Strategy 模式将逻辑封装到一个类里面,通过组合的方式将具体算法的实现在组合对象中实现,再通过委托的方式将抽象接口的实现委托给组合对象实现。


一、策略模式( Strategy 模式)

Strategy 模式的关键就是将算法的逻辑抽象接口(DoAction)封装到一个类中(Context),再通过委托的方式将具体的算法实现委托给具体的 Strategy 类来实现(ConcreteStrategeA类或者oncreteStrategeB类)。UML图如下:
Strategy 模式示意图

二、具体源码

1.Strategy.h

代码如下(示例):

#ifndef _STRATEGY_H_ 
#define _STRATEGY_H_ 

#include <iostream>

class Strategy
{
public:

  Strategy();
  virtual ~Strategy();
  virtual void AlgrithmInterface() = 0;

protected:

private:
};

class ConcreteStrategyA :public Strategy
{
public:

  ConcreteStrategyA();
  virtual ~ConcreteStrategyA();
  void AlgrithmInterface();

protected:

private:
};

class ConcreteStrategyB :public Strategy
{
public:

  ConcreteStrategyB();
  virtual ~ConcreteStrategyB();
  void AlgrithmInterface();

protected:
private:
};

#endif //_STRATEGY_H_

2.Strategy.cpp

代码如下(示例):

#include "Strategy.h"

Strategy::Strategy()
{
}

Strategy::~Strategy()
{
  std::cout << "~Strategy....." << std::endl;
}

void Strategy::AlgrithmInterface()
{
}

ConcreteStrategyA::ConcreteStrategyA()
{
}

ConcreteStrategyA::~ConcreteStrategyA()
{
  std::cout << "~ConcreteStrategyA....." << std::endl;
}

void ConcreteStrategyA::AlgrithmInterface()
{
  std::cout << "test ConcreteStrategyA....." << std::endl;
}

ConcreteStrategyB::ConcreteStrategyB()
{
}

ConcreteStrategyB::~ConcreteStrategyB()
{
  std::cout << "~ConcreteStrategyB....." << std::endl;
}

void ConcreteStrategyB::AlgrithmInterface()
{
  std::cout << "test ConcreteStrategyB....." << std::endl;
}

3.Context.h

代码如下(示例):

#pragma once
#ifndef _CONTEXT_H_ 
#define _CONTEXT_H_

#include "Strategy.h"

class Context
{
public:

  Context(Strategy* stg);
  ~Context();
  void DoAction();

protected:
private:
  //Strategy 通过“组合”(委托)方式实现算法(实现)的异构,而 Template 模式则采取的是继承的方式 *这两个模式的区别也是继承和组合两种实现接口重用的方式的区别
  Strategy* _stg;
};

#endif //_CONTEXT_H_

4.Context.cpp

代码如下(示例):

#include "Context.h"

Context::Context(Strategy* stg)
{
  _stg = stg;
}

Context::~Context()
{
  if (!_stg)
    delete _stg;
}

void Context::DoAction()
{
  _stg->AlgrithmInterface();
}

5.main.cpp

代码如下(示例):

#include "Context.h"

int main(int argc, char* argv[])
{
  Strategy* ps = new ConcreteStrategyA();
  Context* pc = new Context(ps);

  Strategy* ps1 = new ConcreteStrategyB();
  Context* pc1 = new Context(ps1);

  pc->DoAction();
  pc1->DoAction();

  //释放申请的内存
  if (nullptr != pc)
    delete pc;
  if (nullptr != pc1)
    delete pc1;

  return 0;
}

三、运行结果

Strategy 模式运行结果如下:
 Strategy 模式运行结果


总结

从上述内容可以看出, Strategy 模式和 Template 模式解决了类似的问题,两者实际是实现一个抽象接口的两种方式:继承和组合之间的区别。要实现一个抽象接口,继承是一种方式:我们将抽象接口声明在基类中,将具体
的实现放在具体子类中。组合(委托)是另外一种方式:我们将接口的实现放在被组合对象中,将抽象接口放在组合类中。
这两种方式各有优缺点,如下:

  • 继承:易于修改和扩展那些被复用的实现。但是这样破坏了封装性,继承中父类的实现细节暴露给子类了;当父类的实现更改时,其所有子类将不得不随之改变;而且,从父类继承而来的实现在运行期间不能改变(编译期间就已经确定了)。
  • 组合:“黑盒”复用,因为被包含对象的内部细节对外是不可见的,封装性好;另外,实现和抽象的依赖性很小(组合对象和被组合对象之间的依赖性小),可以在运行期间动态定义实现(通过一个指向相同类型的指针,典型的是抽象基类的指针)。但是,这样设计的缺点也是显而易见的,会引起系统中对象过多。

从上面对比中我们可以看出,组合相比继承可以取得更好的效果,因此在面向对象的设计中的有一条很重要的原则就是:优先使用(对象)组合,而非(类)继承(FavorComposition Over Inheritance)


本文参考《设计模式精解-GoF 23 种设计模式解析附 C++实现源码》,对内容进行整理,方便大家学习。如想学习详细内容,请参考此书。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

希望早日退休的程序猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值