设计模式(十四)――策略模式
一、策略模式简介
1、策略模式简介
策略模式定义了算法家族,分别封装起来,让不同算法之间可以互相替换,使算法的变化不会影响到使用算法的客户。
策略模式将算法的逻辑抽象接口(doAction)封装到一个类(Context)里面,通过组合的方式将具体算法的实现在组合对象中实现,再通过委托的方式将抽象接口的实现委托给具体的策略类来实现(ConcreteStrategy)实现。
策略模式是一种定义一系列算法的方法,所有的算法完成的都是相同的工作,只是实现不同。策略模式可以以相同的方式调用所有的算法,减少了各种算法类与使用算法类之间的耦合。
策略模式就是用来封装算法的,但在实践中,发现可以用策略模式来封装几乎任何类型的规则,只要在分析过程中需要在不同时间应用不同的业务规则,就可以考虑使用策略模式处理。
在基本的策略模式中,选择所用具体实现的职责由客户端对象承担,并转给策略模式的Context对象,并没有解除客户端需要选择判断的压力。
2、策略模式角色
Stragegy策略类:定义所有支持的算法的公共接口,当各个实现类中存在着重复的逻辑时,则使用抽象类来封装公共的代码。
ConcreteStrategy具体策略类:继承于Strategy,封装了具体的算法或行为,
Context上下文:用一个ConcreteStrategy来配置,维护一个对Strategy对象的引用
策略模式是对算法的封装,把一系列的算法分别封装到对应的类中,并且这些类实现相同的接口,相互之间可以替换。策略模式中,调用算法的主体封装在了封装类Context中,抽象策略Strategy一般是一个接口,目的只是为了定义规范,而在实际编程中,因为各个具体策略实现类之间难免存在一些相同的逻辑,为了避免重复的代码,常常使用抽象类来担任Strategy的角色,在里面封装公共的代码。
3、策略模式优缺点
策略模式的优点:
A、策略类之间可以*切换,由于策略类实现自同一个抽象,所以策略类之间可以*切换。
B、易于扩展,增加一个新的策略对策略模式来说非常容易,基本上可以在不改变原有代码的基础上进行扩展。
C、避免使用多重条件,如果不使用策略模式,对于所有的算法,必须使用条件语句进行连接,通过条件判断来决定使用哪一种算法
策略模式的缺点:
A、维护各个策略类会给开发带来额外开销
B、客户端必须知道所有的策略类,并自行决定使用哪一个策略类
4、策略模式使用场景
策略模式使用场景:
A、需要使用一个算法的不同变体
B、有几种相似的行为,客户端需要动态地决定使用哪一种,可以使用策略模式。
二、策略模式实现
Context封装类:
#ifndef CONTEXT_H#define CONTEXT_H
#include "Strategy.h"
//封装类
class Context
{
public:
Context(Strategy* strategy)
{
m_strategy = strategy;
}
void doAction()
{
m_strategy->AlgrithmInterface();
}
private:
Strategy* m_strategy;
};
#endif // CONTEXT_H
Strategy抽象策略类:
#ifndef STRATEGY_H#define STRATEGY_H#include <iostream> //抽象策略类class Strategy{public: virtual void AlgrithmInterface() = 0;protected: Strategy(){}//不对外开放接口}; #endif // STRATEGY_H
ConcreteStrategyA具体策略类:
#ifndef CONCRETESTRATEGYA_H#define CONCRETESTRATEGYA_H#include "Strategy.h" //具体策略类class ConcreteStrategyA : public Strategy{public: ConcreteStrategyA(){} void AlgrithmInterface() { std::cout << "ConcreteStrategyA::AlgrithmInterface()" << std::endl; }}; #endif // CONCRETESTRATEGYA_H
ConcreteStrategyB具体策略类:
#ifndef CONCRETESTRATEGYB_H#define CONCRETESTRATEGYB_H#include "Strategy.h" //具体策略类class ConcreteStrategyB : public Strategy{public: ConcreteStrategyB(){} virtual void AlgrithmInterface() { std::cout << "ConcreteStrategyB::AlgrithmInterface()" << std::endl; }}; #endif // CONCRETESTRATEGYB_H
客户调用程序:
#include "Strategy.h"#include "ConcreteStrategyA.h"#include "ConcreteStrategyB.h"#include "Context.h" int main(){ Strategy* pStrategy = new ConcreteStrategyA(); Context* pContext = new Context(pStrategy); pContext->doAction(); delete pStrategy; delete pContext; pStrategy = new ConcreteStrategyB(); pContext = new Context(pStrategy); pContext->doAction(); delete pStrategy; delete pContext; return 0;}
三、策略模式实例
高速缓存(Cache)替换算法,当发生Cache缺失时,Cache控制器必须选择Cache中的一行,并用欲获得的数据来替换。所采用的选择策略就是Cache的替换算法。
策略模式的UML图如下:
ReplaceAlgorithm是一个抽象类,定义了算法的接口。Cache类中需要使用替换算法,因此维护了一个 ReplaceAlgorithm的对象。
Cache封装类:
#ifndef CACHE_H#define CACHE_H#include "ReplaceAlgorithm.h"#include "FIFO_ReplaceAlgorithm.h"#include "LRU_ReplaceAlgorithm.h"#include "Random_ReplaceAlgorithm.h" //Cache替换算法enum RA {LRU, FIFO, RANDOM}; //标签class Cache{public: Cache(enum RA ra) { if(ra == LRU) m_replaceAlgorithm = new LRU_ReplaceAlgorithm(); else if(ra == FIFO) m_replaceAlgorithm = new FIFO_ReplaceAlgorithm(); else if(ra == RANDOM) m_replaceAlgorithm = new Random_ReplaceAlgorithm(); else m_replaceAlgorithm = NULL; } ~Cache() { delete m_replaceAlgorithm; } void replace() { m_replaceAlgorithm->replace(); }private: ReplaceAlgorithm *m_replaceAlgorithm;}; #endif // CACHE_H
ReplaceAlgorithm抽象策略类:
#ifndef REPLACEALGORITHM_H#define REPLACEALGORITHM_H#include <iostream>using namespace std; class ReplaceAlgorithm{public: virtual void replace() = 0;protected: ReplaceAlgorithm(){}}; #endif // REPLACEALGORITHM_H
FIFO_ReplaceAlgorithm具体策略类:
#ifndef FIFO_REPLACEALGORITHM_H#define FIFO_REPLACEALGORITHM_H#include "ReplaceAlgorithm.h" class FIFO_ReplaceAlgorithm : public ReplaceAlgorithm{public: void replace() { cout << "FIFO_ReplaceAlgorithm::replace" << endl; }}; #endif // FIFO_REPLACEALGORITHM_H
LRU_ReplaceAlgorithm具体策略类:
#ifndef LRU_REPLACEALGORITHM_H#define LRU_REPLACEALGORITHM_H#include "ReplaceAlgorithm.h" class LRU_ReplaceAlgorithm : public ReplaceAlgorithm{public: void replace() { cout << "LRU_ReplaceAlgorithm::replace" << endl; }}; #endif // LRU_REPLACEALGORITHM_H
Random_ReplaceAlgorithm具体策略类:
#ifndef RANDOM_REPLACEALGORITHM_H#define RANDOM_REPLACEALGORITHM_H#include "ReplaceAlgorithm.h" class Random_ReplaceAlgorithm : public ReplaceAlgorithm{public: void replace() { cout << "Random_ReplaceAlgorithm::replace" << endl; }}; #endif // RANDOM_REPLACEALGORITHM_H
客户调用程序
#include "Cache.h" int main(){ Cache cache(LRU); //指定标签即可 cache.replace(); return 0;}
Cache封装类在构造函数中使用简单工厂方法,用算法标签指定调用的具体算法策略类,客户端不需要知道具体的算法策略类。
本文出自 “生命不息,奋斗不止” 博客,谢绝转载!