文章目录
前言
Strategy 模式和 Template 模式要解决的问题是相同的,都是为了给业务逻辑具体实现和抽象接口之间的解耦。Strategy 模式将逻辑封装到一个类里面,通过组合的方式将具体算法的实现在组合对象中实现,再通过委托的方式将抽象接口的实现委托给组合对象实现。
一、策略模式( Strategy 模式)
Strategy 模式的关键就是将算法的逻辑抽象接口(DoAction)封装到一个类中(Context),再通过委托的方式将具体的算法实现委托给具体的 Strategy 类来实现(ConcreteStrategeA类或者oncreteStrategeB类)。UML图如下:
二、具体源码
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 模式和 Template 模式解决了类似的问题,两者实际是实现一个抽象接口的两种方式:继承和组合之间的区别。要实现一个抽象接口,继承是一种方式:我们将抽象接口声明在基类中,将具体
的实现放在具体子类中。组合(委托)是另外一种方式:我们将接口的实现放在被组合对象中,将抽象接口放在组合类中。
这两种方式各有优缺点,如下:
- 继承:易于修改和扩展那些被复用的实现。但是这样破坏了封装性,继承中父类的实现细节暴露给子类了;当父类的实现更改时,其所有子类将不得不随之改变;而且,从父类继承而来的实现在运行期间不能改变(编译期间就已经确定了)。
- 组合:“黑盒”复用,因为被包含对象的内部细节对外是不可见的,封装性好;另外,实现和抽象的依赖性很小(组合对象和被组合对象之间的依赖性小),可以在运行期间动态定义实现(通过一个指向相同类型的指针,典型的是抽象基类的指针)。但是,这样设计的缺点也是显而易见的,会引起系统中对象过多。
从上面对比中我们可以看出,组合相比继承可以取得更好的效果,因此在面向对象的设计中的有一条很重要的原则就是:优先使用(对象)组合,而非(类)继承(FavorComposition Over Inheritance)。
本文参考《设计模式精解-GoF 23 种设计模式解析附 C++实现源码》,对内容进行整理,方便大家学习。如想学习详细内容,请参考此书。