場景引入 假如你在A城市,要去B城市旅游,交通方式有以下幾種選擇: 駕車 火車 飛機 不難寫出這樣的代碼: void transport(string method) { if (method == "drive") { // 處理駕車相關業務邏輯 } else if (method == "tra ...
場景引入
假如你在A城市,要去B城市旅游,交通方式有以下幾種選擇:
- 駕車
- 火車
- 飛機
不難寫出這樣的代碼:
void transport(string method)
{
if (method == "drive")
{
// 處理駕車相關業務邏輯
}
else if (method == "train")
{
// 處理乘坐火車相關業務邏輯
}
else
{
// 處理乘坐飛機相關業務邏輯
}
}
想一想,有什麼問題?
屏幕前的你應該已經想到了,如果增加一種交通方式的話,是不是得增加if-else分支?這樣就需要大量的修改,不符合開閉原則。
那怎麼樣能做到在不對源代碼直接修改的前提下增加交通方式呢?答案是:把不同交通方式的業務邏輯抽離出來單獨做成介面。
首先我們要定義一個基類Transportation
,作為這幾個交通方式的父類。這個Transportation
有個純虛函數run
,從Transportation
派生出Drive
、Train
、Plane
等子類(叫做策略類),重寫run
函數。這時的類體系如下:
這樣將來如果需要擴展的話,只需要在從Transportation
類派生出新的子類了。
代碼如下:
class Transportation
{
public:
virtual void run() = 0;
}
class Drive : public Transportation
{
public:
void run() override
{
// 處理駕車相關業務邏輯
}
}
class Train : public Transportation
{
public:
void run() override
{
// 處理乘坐火車相關業務邏輯
}
}
class Plane : public Transportation
{
public:
void run() override
{
// 處理乘坐飛機相關業務邏輯
}
?
此時多態就體現出來了,使用不同的類,調用run
函數,就會做出不同的行為。
那怎麼樣來使用這些策略類呢?我們再新增一個類Context
,可以根據傳入的參數做相應的處理:
class Context
{
Transportation &strategy;
public:
explicit Context(Transportation &strategy) : strategy(strategy) { }
void run()
{
strategy.run();
}
}
定義
策略模式(Strategy Pattern):一個類的行為或其演算法可以在運行時更改的設計模式。(如例子中不同的交通方式)
主要使用場景
有多種演算法,希望避免因為多個if-else分支而帶來的難以維護和擴展的問題。
組成
抽象策略類:定義了不同策略的介面(如例子中的Transportation
)
具體策略類:具體實現抽象策略類的介面(如例子中的Drive
、Train
、Plane
)
環境:根據需要進行決策(如例子中的Context
)
優缺點
優點
- 可維護性、可擴展性高。
- 對客戶隱藏了具體的實現細節
缺點
- 客戶端必須要知道所有的策略類,並自行選擇要用哪一個策略類。