【設計模式】工廠方法模式
阿新 • • 發佈:2020-08-22
工廠方法模式
簡介
為了利用簡單工廠模式且遵循開閉原則,工廠方法模式中不再使用工廠類統一建立所有的具體產品,而是針對不同的產品設計了不同的工廠,每一個工廠只生產特定的產品。
工廠方法模式:定義一個用於建立物件的介面,但是讓子類決定將哪一個類例項化。工廠方法模式讓一個類的例項化延遲到其子類。
結構
實現
實現方式:
- 讓所有產品都遵循同一介面。該介面必須宣告對所有產品都有意義的方法。
- 在建立類中新增一個空的工廠方法。該方法的返回型別必須遵循通用的產品介面。
- 在建立者程式碼中找到對於產品建構函式的所有引用。將它們依次替換為對於工廠方法的呼叫,同時將建立產品的程式碼移入工廠方法。你可能需要在工廠方法中新增臨時引數來控制返回的產品型別。
- 為工廠方法中的每種產品編寫一個建立者子類,然後在子類中重寫工廠方法,並將基本方法中的相關建立程式碼移動到工廠方法中。
- 如果應用中的產品型別太多,那麼為每個產品建立子類並無太大必要,這時你也可以在子類中複用基類中的控制引數。
- 如果程式碼經過上述移動後,基礎工廠方法中已經沒有任何程式碼,你可以將其轉變為抽象類。如果基礎工廠中還有其他語句,你可以將其設定為該方法的預設行為。
#include <iostream> #include <memory> class Product { public: virtual ~Product() {} // virtual virtual std::string Operation() const = 0; }; class ConceteProduct1: public Product { public: std::string Operation() const override { return "{Result of the ConcreteProduct1}"; } }; class ConceteProduct2: public Product { public: std::string Operation() const override { return "{Result of the ConcreteProduct2}"; } }; class Creator { public: virtual ~Creator() {} // virtual virtual Product* FactoryMethod() const = 0; std::string SomeOperation() const { Product* product = this->FactoryMethod(); std::string result = "Creator: The same creator's code has just worked with " + product->Operation(); delete product; return result; } }; class ConcreteCreator1: public Creator { public: Product* FactoryMethod() const override { return new ConceteProduct1(); } }; class ConcreteCreator2: public Creator { public: Product* FactoryMethod() const override { return new ConceteProduct2(); } }; void ClientCode(const Creator& creator) { // ... std::cout << "Client: I'm not aware of the creator's class, but it still works.\n" << creator.SomeOperation() << std::endl; // ... } int main(int argc, char *argv[]) { std::cout << "App: Launched with the ConcreteCreator1.\n"; // Creator* creator = new ConcreteCreator1(); std::shared_ptr<Creator> creator = std::make_shared<ConcreteCreator1>(); ClientCode(*creator); std::cout << std::endl; std::cout << "App: Launched with the ConcreteCreator2.\n"; // Creator* creator = new ConcreteCreator2(); std::shared_ptr<Creator> creator2 = std::make_shared<ConcreteCreator2>(); ClientCode(*creator2); std::cout << std::endl; return 0; }
from __future__ import annotations from abc import ABC, abstractmethod class Creator(ABC): """ """ @abstractmethod def factory_method(self): """ """ pass def some_operation(self) -> str: """ """ product = self.factory_method() # Now, use the product. result = f"Creator: The same creator's code has just worked with {product.operation()}" return result class ConcreteCreator1(Creator): """ """ def factory_method(self) -> ConcreteProduct1: return ConcreteProduct1() class ConcreteCreator2(Creator): def factory_method(self) -> ConcreteProduct2: return ConcreteProduct2() class Product(ABC): """ """ @abstractmethod def operation(self) -> str: pass class ConcreteProduct1(Product): def operation(self) -> str: return "{Result of the ConcreteProduct1}" class ConcreteProduct2(Product): def operation(self) -> str: return "{Result of the ConcreteProduct2}" def client_code(creator: Creator) -> None: """ """ print(f"Client: I'm not aware of the creator's class, but it still works.\n" f"{creator.some_operation()}", end="") if __name__ == "__main__": print("App: Launched with the ConcreteCreator1.") client_code(ConcreteCreator1()) print("\n") print("App: Launched with the ConcreteCreator2.") client_code(ConcreteCreator2())
例項
問題描述
同學們想要進行戶外運動,他們可以選擇打籃球、踢足球或者玩排球。它們分別有籃球保管室、足球保管室和排球保管室管理,只需要去相應的保管室就能拿到相應的球。
問題解答
// Example.cpp
#include <iostream>
// 抽象產品類
class AbstractSportProduct {
public:
virtual ~AbstractSportProduct() {}
virtual void printName() const = 0;
virtual void play() const = 0;
};
// 具體產品類
class Basketball: public AbstractSportProduct {
public:
Basketball() {
printName();
play();
}
void printName() const {
std::cout << "get Basketball" << std::endl;
}
void play() const {
std::cout << "play Basketball" << std::endl;
}
};
// 具體產品類
class Football: public AbstractSportProduct {
public:
Football() {
printName();
play();
}
void printName() const {
std::cout << "get Football" << std::endl;
}
void play() const {
std::cout << "play Football" << std::endl;
}
};
// 具體產品類
class Volleyball: public AbstractSportProduct {
public:
Volleyball() {
printName();
play();
}
void printName() const {
std::cout << "get Volleyball" << std::endl;
}
void play() const {
std::cout << "play Volleyball" << std::endl;
}
};
// 抽象工廠類
class AbstractFactory {
public:
virtual ~AbstractFactory() {}
virtual AbstractSportProduct *getSportProduct() const = 0;
};
// 具體工廠類
class BasketballFactory : public AbstractFactory {
public:
BasketballFactory() {
// ...
}
AbstractSportProduct* getSportProduct() const {
std::cout << "basketball" << std::endl;
return new Basketball();
}
};
// 具體工廠類
class FootballFactory : public AbstractFactory {
public:
FootballFactory() {
// ...
}
AbstractSportProduct* getSportProduct() const {
std::cout << "football" << std::endl;
return new Football();
}
};
// 具體工廠類
class VolleyballFactory : public AbstractFactory {
public:
VolleyballFactory() {
// ...
}
AbstractSportProduct* getSportProduct() const {
std::cout << "volleyball" << std::endl;
return new Volleyball();
}
};
int main(int argc, char* argv[]) {
AbstractFactory* fac = nullptr;
AbstractSportProduct* pro = nullptr;
fac = new BasketballFactory();
pro = fac->getSportProduct();
std::cout << std::endl;
fac = new FootballFactory();
pro = fac->getSportProduct();
std::cout << std::endl;
fac = new VolleyballFactory();
pro = fac->getSportProduct();
std::cout << std::endl;
delete fac;
delete pro;
return 0;
}
總結
優點
- 工廠方法模式更加符合開閉原則,它是使用頻率最高的設計模式之一,是很多開源框架和類庫的核心模式。
- 工廠方法模式更加符合單一職責原則,你可以將產品建立程式碼放在程式的單一位置,從而使程式碼更加容易維護。
- 工廠方法用於建立客戶所需產品,同時向客戶隱藏某個具體產品類將被例項化的細節,使用者只需要關心所需產品對應的工廠。
- 工廠自主決定建立何種產品,並且建立過程封裝在具體工廠物件內部,多型性設計是工廠模式的關鍵。
缺點
- 新增新產品時需要同時新增新的產品工廠,系統中的類的數量成對增加,增加了系統複雜度和額外開銷。
場景
- 當你在編寫程式碼時,如果無法預知物件確切類別和其依賴關係時,可使用工廠方法模式。
- 如果你希望使用者能擴充套件你軟體庫或者框架的內部元件,可使用工廠方法模式。
- 如果你希望複用現有物件來節省系統資源,而不是每次都重新建立物件,可使用工廠方法模式。
與其他模式的關係
- 在許多設計工作的初期都會使用工廠方法模式(較為簡單,而且方便通過子類進行定製),隨後演變為使用抽象工廠模式、原型模式或建造者模式。
- 抽象工廠模式通常基於一組工廠方法,但你也可以使用原型模式來生成這些類的方法。
- 你可以同時使用工廠方法模式和迭代器模式來讓子類集合返回不同型別的迭代器,並使得迭代器與集合相匹配。
- 工廠方法模式是模板方法模式的一直特殊形式,同時,工廠方法可以作為一個大型模板方法中的一個步驟。