別隻知道策略模式+簡單工廠,試試更香的策略模式+抽象工廠!

一匹夫發表於2021-03-16

 

我的相關博文 

三種工廠模式詳解

 

策略模式

在GOF的《設計模式:可複用物件導向軟體的基礎》一書中對策略模式是這樣說的:

定義一系列的演算法,把它們一個個封裝起來,並且使它們可相互替換。該模式使得演算法可獨立於使用它的客戶而變化。

 

策略模式為了適應不同的需求,只把變化點封裝了,這個變化點就是實現不同需求的演算法,例如加班工資,不同的加班情況,有不同的計算加班工資的方法。

我們不能在程式中將計算工資的演算法進行硬編碼,而能夠自由變化。

這就是策略模式。

 

 

 

 

實驗1 策略模式+簡單工廠

程式碼

#include <iostream>
using namespace std;

// Define the strategy type
typedef enum StrategyType
{
    StrategyA,
    StrategyB,
    StrategyC
}STRATEGYTYPE;

// The abstract strategy
class Strategy
{
public:
    virtual void AlgorithmInterface(int x, int y) = 0;
    virtual ~Strategy() = 0; 
};

Strategy::~Strategy()
{}

class ConcreteStrategyA : public Strategy
{
public:
    void AlgorithmInterface(int x, int y)
    {
        cout << "I am from ConcreteStrategyA: result=X+Y, = " << x+y << endl;
    }

    ~ConcreteStrategyA(){
        cout << "~ConcreteStrategyA()." << endl;
    }
};

class ConcreteStrategyB : public Strategy
{
public:
    void AlgorithmInterface(int x, int y)
    {
        cout << "I am from ConcreteStrategyB: result=X*Y, = " << x*y << endl;
    }

    ~ConcreteStrategyB(){
        cout << "~ConcreteStrategyB()." << endl;
    }
};

class ConcreteStrategyC : public Strategy
{
public:
    void AlgorithmInterface(int x, int y)
    {
        cout << "I am from ConcreteStrategyC: result=X-Y, = " << x-y << endl;
    }

    ~ConcreteStrategyC(){
        cout << "~ConcreteStrategyC()." << endl;
    }
};

// 使用者類 : 使用演算法的使用者
class Context
{
public:
    // 該建構函式內使用簡單工廠模式
    Context(STRATEGYTYPE strategyType)
    {
        switch (strategyType)
        {
        case StrategyA:
            pStrategy = new ConcreteStrategyA;
            break;

        case StrategyB:
            pStrategy = new ConcreteStrategyB;
            break;

        case StrategyC:
            pStrategy = new ConcreteStrategyC;
            break;

        default:
            break;
        }
    }

    ~Context()
    {
        if (pStrategy) 
            delete pStrategy;
    }

    void ContextInterface(int x, int y) // 定義一個介面來讓Stategy訪問使用者的資料
    {
        if (pStrategy)
            pStrategy->AlgorithmInterface(x, y);
    }

private:
    Strategy *pStrategy; // 維護一個對Stategy物件的引用或指標
    int a;               // 私有資料,這是使用者資料,該使用者是獨立於演算法的使用者,使用者不需要了解演算法內部的資料結構
    int b;
};

int main()
{
    Context *pContext = new Context(StrategyA);
    pContext->ContextInterface(100, 6);

    if (pContext) 
        delete pContext;
}

上述的例子是策略模式,我們還能看到一點簡單工廠模式的影子。

百度到的絕大多數都是這種例子了。 這個程式碼完美嗎?看下GoF的要領:

如果我們需要新增新的演算法,我們需要修改Context類的建構函式,在裡面新增新的演算法,這顯然不符合GoF採用擴充套件、子類化的精要。

所以引出了我下面的策略模式+抽象工廠的解決方案。

 

 

實驗2 策略模式+抽象工廠

程式碼

#include <iostream>
using namespace std;


// The abstract strategy
class Strategy
{
public:
    virtual void AlgorithmInterface(int x, int y) = 0;
    virtual ~Strategy() = 0; 
};

Strategy::~Strategy()
{}

class ConcreteStrategyA : public Strategy
{
public:
    void AlgorithmInterface(int x, int y)
    {
        cout << "I am from ConcreteStrategyA: result=X+Y, = " << x+y << endl;
    }

    ~ConcreteStrategyA(){
        cout << "~ConcreteStrategyA().析夠" << endl;
    }
};

class ConcreteStrategyB : public Strategy
{
public:
    void AlgorithmInterface(int x, int y)
    {
        cout << "I am from ConcreteStrategyB: result=X*Y, = " << x*y << endl;
    }

    ~ConcreteStrategyB(){
        cout << "~ConcreteStrategyB().析夠" << endl;
    }
};

class ConcreteStrategyC : public Strategy
{
public:
    void AlgorithmInterface(int x, int y)
    {
        cout << "I am from ConcreteStrategyC: result=X-Y, = " << x-y << endl;
    }

    ~ConcreteStrategyC(){
        cout << "~ConcreteStrategyC().析夠" << endl;
    }
};

// 使用者類 : 使用演算法的使用者
class Context
{
public:
    // 該建構函式內使用簡單工廠模式
    Context(Strategy* paraStrategy)
    {
        pStrategy = paraStrategy;
    }

    ~Context()
    {
        // 這裡不需要析夠pStrategy, pStrategy對應物件的析夠會在delete pAbstractStrategyFactory時進行。
        // 即,銷燬具體某個策略工廠物件時會負責析夠具體的策略物件。所以這裡就不需要了。
    }

    void ContextInterface(int x, int y) // 定義一個介面來讓Stategy訪問使用者的資料
    {
        if (pStrategy)
            pStrategy->AlgorithmInterface(x, y);
    }

private:
    Strategy *pStrategy; // 維護一個對Stategy物件的引用或指標
    int a;               // 私有資料,這是使用者資料,該使用者是獨立於演算法的使用者,使用者不需要了解演算法內部的資料結構
    int b;
};



// 點評shape類: 一條產品線下的產品,通常存在共性,
// 也就是說,一個產品抽象類通常是需要的,而不是必須的。   

class AbstractStrategyFactory   // 抽象工廠這裡可以實現多個純虛方法
{
public:
    virtual Strategy* createStrategy(string Strategy)=0;
    virtual ~AbstractStrategyFactory(){}
};
  
class StrategyA_Factory:public AbstractStrategyFactory
{
Strategy *pStrategy;
public:
    StrategyA_Factory():pStrategy(NULL)
    {}
    Strategy* createStrategy(string Strategy)
    {
        if(Strategy == "StrategyA"){
            pStrategy = new ConcreteStrategyA();
            return pStrategy;
        }
        return NULL;
    }
    ~StrategyA_Factory()
    {
        cout << "~StrategyA_Factory(). 析夠" << endl;
        if(pStrategy)
            delete pStrategy;
    }
};

class StrategyB_Factory:public AbstractStrategyFactory
{
Strategy *pStrategy;
public:
    StrategyB_Factory():pStrategy(NULL)
    {}
    Strategy* createStrategy(string Strategy)
    {
        if(Strategy == "StrategyB"){
            pStrategy = new ConcreteStrategyB();
            return pStrategy;
        }
        return NULL;
    }
    ~StrategyB_Factory()
    {
        if(pStrategy)
            delete pStrategy;
    }
};

class StrategyC_Factory:public AbstractStrategyFactory
{
Strategy *pStrategy;
public:
    StrategyC_Factory():pStrategy(NULL)
    {}
    Strategy* createStrategy(string Strategy)
    {
        if(Strategy == "StrategyC"){
            pStrategy = new ConcreteStrategyC();
            return pStrategy;
        }
        return NULL;
    }
    ~StrategyC_Factory()
    {
         if(pStrategy)
            delete pStrategy;       
    }
};

int main(int argc, char *argv[])
{
    AbstractStrategyFactory* pAbstractStrategyFactory;  // 建立抽象工廠指標
 
    pAbstractStrategyFactory = new StrategyA_Factory();       // 建立策略A的工廠
    Strategy* pStrategy = pAbstractStrategyFactory->createStrategy("StrategyA");  //使用策略A工廠來生產出策略A
    if(pStrategy == NULL)
    {
        cout << "pStrategy is NULL" << endl;
    }
    else
    {
    // 供使用者來使用策略A : 使用者使用策略A 和 策略A的實現,是鬆耦合的。
    Context *pContext = new Context(pStrategy);
    pContext->ContextInterface(100, 6);

    delete pAbstractStrategyFactory;

    if (pContext) 
        delete pContext;
    }

    return 0;
  
}

編譯執行:

 

此時,如果要新增演算法,那我覺得可以採用擴充套件、子類化的解決方案了,而不用像本博文上一個例子那樣,去修改已有的程式碼了。

當然,這樣的設計會導致程式碼量變大,所以一切都需要權衡,適合自己的就是最好的。

 

 

 

.

相關文章