設計模式之工廠模式
本文轉載自微信公眾號「程序喵大人」,作者程序喵大人 。轉載本文請聯系程序喵大人公眾號。
01 簡單工廠方法
簡單工廠方法可能是最常見的工廠類創建型模式了,其中有幾個角色,一個是抽象產品角色,一個是具體產品角色,多個具體產品都可以。抽象成同一個抽象產品。拿操作系統舉例,操作系統作為一個抽象產品,它有幾種具體產品角色,有Windows操作系統,有Android操作系統,有iOS操作系統。有一個操作系統的工廠,工廠可以根據不同的需求生產出不同內核的操作系統,這個操作系統的工廠就是最后一個角色:工廠角色。
- #include <iostream>
- enum class BallEnum { BasketBall = 1, SocketBall = 2 };
- class Ball {
- public:
- Ball() {}
- virtual ~Ball() {}
- virtual void Play() {}
- };
- class BasketBall : public Ball {
- public:
- void Play() override { std::cout << "play basketball \n"; }
- };
- class SocketBall : public Ball {
- public:
- void Play() override { std::cout << "play socketball \n"; }
- };
- class SimpleFactory {
- public:
- static Ball* CreateBall(BallEnum type);
- };
- Ball* SimpleFactory::CreateBall(BallEnum type) {
- switch (type) {
- case BallEnum::BasketBall:
- return new BasketBall();
- case BallEnum::SocketBall:
- return new SocketBall();
- }
- return nullptr;
- }
- int main() {
- Ball* basket = SimpleFactory::CreateBall(BallEnum::BasketBall);
- basket->Play();
- Ball* socket = SimpleFactory::CreateBall(BallEnum::SocketBall);
- socket->Play();
- return 0;
- }
在簡單工廠方法中,有一個專門的工廠類,根據不同的參數返回不同具體產品類的實例,這些具體產品可以抽象出同一個抽象產品,即有一個共同的父類。 通過上述代碼您可能也看到了簡單工廠方法的優點,實現了對象的創建和使用邏輯分離,只需要傳入不同參數,就可以獲得特定具體類的實例。但簡單工廠方法也有些缺點,當增加了新的產品,就需要修改工廠類的創建邏輯,如果產品類型較多,就可能造成工廠類邏輯過于復雜,不利于系統的維護,適用于具體產品類型比較少并且以后基本不會新加類型的場景,這樣工廠類業務邏輯不會太過復雜。
02 工廠方法模式
為了解決上面簡單工廠方法模式的缺點,進一步抽象出了工廠方法模式,工廠類不再負責所有產品的構建,每一個具體產品都有一個對應的工廠,這樣在新加產品時就不會改動已有工廠類的創建邏輯。這些工廠也會抽象出一個抽象工廠。可以理解為有四種角色,抽象產品,具體產品,抽象工廠,具體工廠,其實就是把簡單工廠模式中的工廠類做進一步抽象,看代碼吧:
- #include <iostream>
- enum class BallEnum { BasketBall = 1, SocketBall = 2 };
- class Ball {
- public:
- Ball() {}
- virtual ~Ball() {}
- virtual void Play() {}
- };
- class BasketBall : public Ball {
- public:
- void Play() override { std::cout << "play basketball \n"; }
- };
- class SocketBall : public Ball {
- public:
- void Play() override { std::cout << "play socketball \n"; }
- };
- class FactoryBase {
- public:
- virtual ~FactoryBase() {}
- virtual Ball* CreateBall() = 0;
- };
- class BasketBallFactory : public FactoryBase {
- public:
- Ball* CreateBall() override { return new BasketBall(); }
- };
- class SocketBallFactory : public FactoryBase {
- public:
- Ball* CreateBall() override { return new SocketBall(); }
- };
- int main() {
- FactoryBase* factory;
- BallEnum ball_type = BallEnum::SocketBall;
- switch (ball_type) {
- case BallEnum::BasketBall:
- factory = new BasketBallFactory();
- break;
- case BallEnum::SocketBall:
- factory = new SocketBallFactory();
- break;
- }
- Ball* ball = factory->CreateBall();
- ball->Play();
- return 0;
- }
工廠模式提高了系統的可擴展性,完全符合開閉原則,當新加具體產品時,完全不會對已有系統有任何修改。當不知道以后會有多少具體產品時可以考慮使用工廠模式,因為不會降低現有系統的穩定性。但是它也有缺點,每當新加一個產品時,不僅需要新加一個對應的產品類,同時還需要新加一個此產品對應的工廠,系統的復雜度比較高。怎么解決呢,可以再抽象一下:
03 抽象工廠模式
在工廠方法中,每一個抽象產品都會有一個抽象工廠,這樣新增一個產品時都會新增兩個類,一個是具體產品類,一個是具體工廠類,我們可以考慮多個抽象產品對應一個抽象工廠,這樣可以有效減少具體工廠類的個數,見如下代碼:
- #include <iostream>
- enum class BallEnum { BasketBall = 1, SocketBall = 2 };
- class Ball {
- public:
- Ball() {}
- virtual ~Ball() {}
- virtual void Play() {}
- };
- class BasketBall : public Ball {
- public:
- void Play() override { std::cout << "play basketball \n"; }
- };
- class SocketBall : public Ball {
- public:
- void Play() override { std::cout << "play socketball \n"; }
- };
- class Player {
- public:
- Player() {}
- virtual ~Player() {}
- virtual void Name() {}
- };
- class BasketBallPlayer : public Player {
- public:
- void Name() override { std::cout << "BasketBall player \n"; }
- };
- class SocketBallPlayer : public Player {
- public:
- void Name() override { std::cout << "SocketBall player \n"; }
- };
- class FactoryBase {
- public:
- virtual ~FactoryBase() {}
- virtual Ball* CreateBall() = 0;
- virtual Player* CreatePlayer() = 0;
- };
- class BasketBallFactory : public FactoryBase {
- public:
- Ball* CreateBall() override { return new BasketBall(); }
- Player* CreatePlayer() override { return new BasketBallPlayer(); }
- };
- class SocketBallFactory : public FactoryBase {
- public:
- Ball* CreateBall() override { return new SocketBall(); }
- Player* CreatePlayer() override { return new SocketBallPlayer(); }
- };
- int main() {
- FactoryBase* factory;
- BallEnum ball_type = BallEnum::SocketBall;
- switch (ball_type) {
- case BallEnum::BasketBall:
- factory = new BasketBallFactory();
- break;
- case BallEnum::SocketBall:
- factory = new SocketBallFactory();
- break;
- }
- Ball* ball = factory->CreateBall();
- Player* player = factory->CreatePlayer();
- ball->Play();
- player->Name();
- return 0;
- }
總結
系統的復雜度不會被消除,只能被轉移。系統總會有穩定部分和不穩定部分,只是我們要合理選擇好邊界,認真思考,考慮好將哪部分打造成穩定部分,哪部分打造成不穩定部分。簡單工廠方法模式中if-else的邏輯在工廠類里,如果這里在新增一個產品時有bug可能導致所有產品都創建失敗,這里是不穩定部分,所以有了工廠方法模式,將工廠類內部打造成穩定部分,將不穩定的邏輯轉移到外面。