C++ 策略模式 - 來一場(chǎng)說走就走的旅行

策略模式(Strategy Pattern)定義了一系列算法,把它們一個(gè)個(gè)封裝起來,并且使其可以互相替換。Strategy 可以使算法獨(dú)立于使用算法的客戶端。
1
模式結(jié)構(gòu)
UML 結(jié)構(gòu)圖:

Context(環(huán)境角色):持有一個(gè)對(duì) Strategy 的引用,最終給客戶端調(diào)用。
Strategy(抽象策略):定義了一個(gè)公共接口,讓不同的算法以不同的方式來實(shí)現(xiàn)。通過這個(gè)接口,Context 可以調(diào)用不同的算法。
ConcreteStrategy(具體策略):實(shí)現(xiàn) Strategy 定義的接口,提供具體算法的實(shí)現(xiàn)。
2
優(yōu)缺點(diǎn)
各自使用封裝的算法,可以很容易地引入新的算法來滿足相同的接口。
由于實(shí)現(xiàn)的是同一個(gè)接口,所以策略之間可以自由切換。
Strategy 使客戶端能夠選擇所需的算法,而無需使用 switch/case 或 if/else 語句。
算法的細(xì)節(jié)完全封裝在 Strategy 類中,因此,可以在不影響 Context 類的情況下更改算法的實(shí)現(xiàn)。
客戶端必須知道所有的策略,了解它們之間的區(qū)別,以便適時(shí)選擇恰當(dāng)?shù)乃惴ā?/p>
策略模式將造成產(chǎn)生很多策略類,可以通過使用享元模式在一定程度上減少對(duì)象的數(shù)量。
3
適用場(chǎng)景
多個(gè)類有不同的表現(xiàn)形式,每種表現(xiàn)形式可以獨(dú)立成單獨(dú)的算法。
需要在不同情況下使用不同的算法,以后算法可能還會(huì)增加。
對(duì)客戶端隱藏具體算法的實(shí)現(xiàn)細(xì)節(jié),彼此完全獨(dú)立。
4
案例分析
說走就走的旅行 - 出行方式

每天,我們做著同樣的工作,遇見同樣的人,吃著同樣的食物 ...... 日復(fù)一日,年復(fù)一年!當(dāng)生活陷入重復(fù),想遇到新鮮的人,新鮮的事,為蒼白的生活添加一些色彩,何不來一場(chǎng)說走就走的旅行!
要出去玩,有很多種出行方式,比如:自行車、公交、自駕、火車、飛機(jī)等,如何選擇最合適的呢?
如果離家近,又怕堵車,可以騎自行車。
如果離家遠(yuǎn),但想省錢,早點(diǎn)出發(fā),可以乘公交車。
如果有車,并且不介意支付停車費(fèi),可以選擇自駕。
如果沒有車,但趕時(shí)間,可以乘出租車。
…...
這里的每一種出行方式都是一種具體的策略,至于如何選擇,需要基于成本、便利和時(shí)間之間的權(quán)衡。
5
代碼實(shí)現(xiàn)
抽象策略由交通工具表示,它包含了一個(gè) Run()?接口,用于提供出行方式:
//?strategy.h
#ifndef?STRATEGY_H
#define?STRATEGY_H
//?出行策略
class?ITransport
{
public:
????virtual?~ITransport()?{}
????virtual?void?Run()?=?0;
};
#endif?//?STRATEGY_H
具體的出行策略有很多種,像自行車、汽車、火車:
//?concrete_strategy.h
#include?"strategy.h"
#include?
//?自行車
class?Bike?:?public?ITransport
{
public:
????void?Run()?override?{?
????????std::cout?<"By?bike"?<std::endl;
????}
};
//?汽車
class?Car?:?public?ITransport
{
public:
????void?Run()?override?{?
????????std::cout?<"By?car"?<std::endl;
????}
};
//?火車
class?Train?:?public?ITransport
{
public:
????void?Run()?override?{
????????std::cout?<"By?train"?<std::endl;
????}
};
#endif?//?CONCRETE_STRATEGY_H
在這里,可以將環(huán)境角色理解為旅行者,它可以選擇具體的出行工具。而根據(jù)工具的不同,出行方式也有所不同(在內(nèi)部,Trave() 最終調(diào)用的是 ITransport 的相應(yīng)方法):
//?context.h
#ifndef?CONTEXT_H
#define?CONTEXT_H
#include?"strategy.h"
//?旅行者
class?Tourists
{
public:
????Tourists(ITransport?*transport)?{?
????????m_pTransport?=?transport;
????}
????void?Travel()?{
????????if?(nullptr?!=?m_pTransport)
????????????m_pTransport->Run();?
????}
private:
????ITransport?*m_pTransport?=?nullptr;
};
#endif?//?CONTEXT_H
旅程開始,盡情享受吧:
注意:策略之間可以相互替換,比如張三可以騎自行車,也可以開車,或者是坐火車,其他人也一樣。
//?main.cpp
#include?"context.h"
#include?"concrete_strategy.h"
#ifndef?SAFE_DELETE
#define?SAFE_DELETE(p)?{?if(p){delete?p;?p=nullptr;}?}
#endif
int?main()
{
????ITransport?*bike?=?new?Bike();
????ITransport?*car?=?new?Car();
????ITransport?*train?=?new?Train();
????//?張三騎自行車、李四開車、王五坐火車
????Tourists?*zhangsan?=?new?Tourists(bike);
????Tourists?*lisi?=?new?Tourists(car);
????Tourists?*wangwu?=?new?Tourists(train);
????zhangsan->Travel();
????lisi->Travel();
????wangwu->Travel();
????SAFE_DELETE(bike);
????SAFE_DELETE(car);
????SAFE_DELETE(train);
????SAFE_DELETE(zhangsan);
????SAFE_DELETE(lisi);
????SAFE_DELETE(wangwu);
????getchar();
????return?0;
}
輸出如下:
By bike
By car
By train
·END·

