別隻知道策略模式+簡單工廠,試試更香的策略模式+抽象工廠!
阿新 • • 發佈: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; }
編譯執行:
此時,如果要新增演算法,那我覺得可以採用擴充套件、子類化的解決方案了,而不用像本博文上一個例子那樣,去修改已有的程式碼了。
當然,這樣的設計會導致程式碼量變大,所以一切都需要權衡,適合自己的就是最好的。