策略模式

来源:互联网 发布:什么是数据审计追踪 编辑:程序博客网 时间:2024/06/05 21:55
1.定义
策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化。

2.UML图



涉及的角色:
    抽象策略类(IStrategy): 它是一个接口,可以定义若干个抽象方法。
    具体策略类(ConcreteStrategy):具体策略类实现了抽象策略类中的抽象方法。
上下文类(Context):是依赖抽象策略方法的类,上下文中包含有策略声明的变量。上下文中提供一个方法,该方法委托策略变量调用具体策略所重写的策略接口中的方法。

3.代码实现
事例: (该事例改编自一道网络设计模式面试题)
    如现在你是一个设计师,你正在设计一种空调。但是你们的空调要支持3种模式。冷风模式(ColdWind), 热风模式(WarmWind),无风模式(NoWind)。
当选择ColdWind模式,将输送冷风;当选择WarmWind模式,将输送热风;在选择NoWind模式时,空调什么都不做。你将考虑如何为空调设计应用程序?如果将来空调需要增加支持新的模式呢?
这道面试题,其实可以用各种模式实现,然而在这里我理解策略模式比较合适。我们将冷风模式,和热风模式以及无风模式可以理解为各种不同的算法。显然策略模式非常符合。
这里ColdWind, WarmWind, NoWind 其实就是ConcreteStrategy。 IWnd是抽象策略类。
#include <iostream>using namespace std;#define SAFE_RELEASE(_p){ if((_p)){ delete (_p); (_p) = NULL;} }//抽象策略类class IWind{public:virtual ~IWind() {}virtual void blowWind() = 0;};//具体策略类class ColdWind : public IWind{public:virtual void blowWind() { cout << "blow cold wind" << endl; }};//具体策略类class WarmWind : public IWind{public:virtual void blowWind() { cout << "blow warm wind" << endl; }};//具体策略类class NoWind : public IWind{public:virtual void blowWind() { cout << "no wind" << endl; }};//上下文类class WindMode{public:void SetWind(IWind* pWind) { m_pWind = pWind; }void blowWind() { m_pWind->blowWind(); }private:IWind*  m_pWind;};//最后客户端代码int main(int argc, char* argv[]){WindMode* pWindMode = new WindMode();ColdWind* pColdWind = new ColdWind();WarmWind* pWarmWind = new WarmWind();NoWind* pNoWind = new NoWind();pWindMode->SetWind(pColdWind);pWindMode->blowWind();pWindMode->SetWind(pWarmWind);pWindMode->blowWind();pWindMode->SetWind(pNoWind);pWindMode->blowWind();SAFE_RELEASE(pWindMode);SAFE_RELEASE(pWarmWind);SAFE_RELEASE(pColdWind);SAFE_RELEASE(pNoWind);system("pause");return 0;}

4.优缺点
策略模式有下面的一些优点:
1) 相关算法系列 Strategy类层次为Context定义了一系列的可供重用的算法或行为。 继承有助于析取出这些算法中的公共功能。
2) 提供了可以替换继承关系的办法: 继承提供了另一种支持多种算法或行为的方法。你可以直接生成一个Context类的子类,从而给它以不同的行为。但这会将行为硬行编制到 Context中,而将算法的实现与Context的实现混合起来,从而使Context难以理解、难以维护和难以扩展,而且还不能动态地改变算法。最后你得到一堆相关的类 , 它们之间的唯一差别是它们所使用的算法或行为。 将算法封装在独立的Strategy类中使得你可以独立于其Context改变它,使它易于切换、易于理解、易于扩展。
3) 消除了一些if else条件语句 :策略模式提供了用条件语句选择所需的行为以外的另一种选择。当不同的行为堆砌在一个类中时 ,很难避免使用条件语句来选择合适的行为。将行为封装在一个个独立的Strategy类中消除了这些条件语句。含有许多条件语句的代码通常意味着需要使用策略模式。
4) 实现的选择 策略模式可以提供相同行为的不同实现。客户可以根据不同时间/空间权衡取舍要求从不同策略中进行选择。

策略模式缺点:
1)客户端必须知道所有的策略类,并自行决定使用哪一个策略类:  本模式有一个潜在的缺点,就是一个客户要选择一个合适的Strategy就必须知道这些Strategy到底有何不同。此时可能不得不向客户暴露具体的实现问题。因此仅当这些不同行为变体与客户相关的行为时 , 才需要使用策略模式。
2 ) Strategy和Context之间的通信开销 :无论各个ConcreteStrategy实现的算法是简单还是复杂, 它们都共享Strategy定义的接口。因此很可能某些 ConcreteStrategy不会都用到所有通过这个接口传递给它们的信息;简单的 ConcreteStrategy可能不使用其中的任何信息!这就意味着有时Context会创建和初始化一些永远不会用到的参数。如果存在这样问题 , 那么将需要在Strategy和Context之间更进行紧密的耦合。
3 )策略模式将造成产生很多策略类:可以通过使用享元模式在一定程度上减少对象的数量。 增加了对象的数目 Strategy增加了一个应用中的对象的数目。有时你可以将 Strategy实现为可供各Context共享的无状态的对象来减少这一开销。任何其余的状态都由 Context维护。Context在每一次对Strategy对象的请求中都将这个状态传递过去。共享的 Strategy不应在各次调用之间维护状态。

备注:策略模式的好处是可以动态改变行为;桥接模式的好处是前端类和后端类可以独立修改,互不影响。前者强调算法可以分离,后者强调抽象与现实分离。
0 0
原创粉丝点击