1. 程式人生 > >【設計模式】策略模式

【設計模式】策略模式

concrete 方法 行為 無法 策略模式 避免 mint his 多態

1、定義

1.1標準定義

策略模式(StrategyPattern)是一種比較簡單的模式,也叫做政策模式(PolicyPattern)。其定義如下:
Defineafamilyofalgorithms,encapsulateeachone,andmaketheminterchangeable.(定義一組算法,將每個算法都封裝起來,並且使它們之間可以互換。)

1.2通用類圖

技術分享

策略模式使用的就是面向對象的繼承和多態機制,非常容易理解和掌握,我們再來看看策略模式的三個角色:
●Context封裝角色
它也叫做上下文角色,起承上啟下封裝作用,屏蔽高層模塊對策略、算法的直接訪問,封裝可能存在的變化。
●Strategy抽象策略角色
策略、算法家族的抽象,通常為接口,定義每個策略或算法必須具有的方法和屬性。各位看官可能要問了,類圖中的AlgorithmInterface是什麽意思,嘿嘿,algorithm運算法則的意思,結合起來意思就明白了吧。
●ConcreteStrategy具體策略角色
實現抽象策略中的操作,該類含有具體的算法。

2、實現

2.1類圖

技術分享

Strategy模式將邏輯(算法)封裝到一個類(Context)裏面,通過組合的方式將具體算法的實現在組合對象中實現,再通過委托的方式將抽象接口的實現委托給組合對象實現。將算法的邏輯抽象接口(DoAction)封裝到一個類中(Context),再通過委托的方式將具體的算法實現委托給具體的Strategy類來實現(ConcreteStrategeA類)。

Stragegy類,定義所有支持的算法的公共接口。
ConcreteStrategy類,封裝了具體的算法或行為,繼承於Strategy。
Context類,用一個ConcreteStrategy來配置,維護一個對Strategy對象的引用。

2.2代碼

2.2.1策略類

//Strategy.h

#ifndef _STRATEGY_H_
#define _STRATEGY_H_

class Strategy
{
public:
  ~Strategy();
  virtual void AlgrithmInterface() = 0;
protected:
  Strategy();
private:
};

class ConcreteStrategyA: public Strategy
{
public:
  ConcreteStrategyA();
  ~ConcreteStrategyA();
  virtual void 
AlgrithmInterface(); protected: private: }; class ConcreteStrategyB: public Strategy { public:   ConcreteStrategyB();   ~ConcreteStrategyB();   virtual void AlgrithmInterface(); protected: private: }; /*這個類是Strategy模式的關鍵, 也是Strategy模式和Template模式的根本區別所在。 *Strategy通過“組合”(委托)方式實現算法(實現)的異構, 而Template模式則采取的是繼承的方式 這兩個模式的區別也是繼承和組合兩種實現接口重用的方式的區別 */ class Context { public:   Context(Strategy* );   ~Context();   void DoAction(); private:   Strategy *_strategy; }; #endif
//Strategy.cpp

#include "Strategy.h"
#include "iostream"

usingnamespace std;

Strategy::Strategy(){}

Strategy::~Strategy(){}

ConcreteStrategyA::ConcreteStrategyA(){}

ConcreteStrategyA::~ConcreteStrategyA(){}

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

ConcreteStrategyB::ConcreteStrategyB(){}

ConcreteStrategyB::~ConcreteStrategyB(){}

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

Context::Context(Strategy *strategy)
{
  this->_strategy = strategy;
}

Context::~Context()
{
  delete this->_strategy;
}

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

2.2.3調用

//main.cpp

#include"Strategy.h"

intmain()
{
/*
Strategy模式和Template模式實際是實現一個抽象接口的兩種方式:繼承和組合之間的區別。
要實現一個抽象接口,繼承是一種方式:我們將抽象接口聲明在基類中,將具體的實現放在具體子類中。
組合(委托)是另外一種方式:我們將接口的實現放在被組合對象中,將抽象接口放在組合類中。
這兩種方式各有優缺點
*/
//策略A與B可替換
  Strategy *pStr = new ConcreteStrategyA();
  Context *pcon = new Context(pStr);
  pcon->DoAction();

  pStr = new ConcreteStrategyB();
  pcon = new Context(pStr);
  pcon->DoAction();

  return 0;
}

3、優缺點

3.1優點

算法可以自由切換
這是策略模式本身定義的,只要實現抽象策略,它就成為策略家族的一個成員,通過封裝角色對其進行封裝,保證對外提供可自由切換的策略。
避免使用多重條件判斷
如果沒有策略模式,我們想想看會是什麽樣子?一個策略家族有5個策略算法,一會要使用A策略,一會要使用B策略,怎麽設計呢?使用多重的條件語句?多重條件語句不易維護,而且出錯的概率大大增強。使用策略模式後,可以由其他模塊決定采用何種策略,策略家族對外提供的訪問接口就是封裝類,簡化了操作,同時避免了條件語句判斷。
擴展性良好
這甚至都不用說是它的優點,因為它太明顯了。在現有的系統中增加一個策略太容易了,只要實現接口就可以了,其他都不用修改,類似於一個可反復拆卸的插件,這大大地符合了OCP原則。

3.2缺點

策略類數量增多
每一個策略都是一個類,復用的可能性很小,類數量增多。
所有的策略類都需要對外暴露
上層模塊必須知道有哪些策略,然後才能決定使用哪一個策略,這與迪米特法則是相違背的,我只是想使用了一個策略,我憑什麽就要了解這個策略呢?那要你的封裝類還有什麽意義?這是原裝策略模式的一個缺點,幸運的是,我們可以使用其他模式來修正這個缺陷,如工廠方法模式、代理模式或享元模式。

4、應用場景

多個類只有在算法或行為上稍有不同的場景。
算法需要自由切換的場景。
例如,算法的選擇是由使用者決定的,或者算法始終在進化,特別是一些站在技術前沿的行業,連業務專家都無法給你保證這樣的系統規則能夠存在多長時間,在這種情況下策略模式是你最好的助手。
需要屏蔽算法規則的場景。
現在的科技發展得很快,人腦的記憶是有限的(就目前來說是有限的),太多的算法你只要知道一個名字就可以了,傳遞相關的數字進來,反饋一個運算結果,萬事大吉。

【設計模式】策略模式