c++++原型模式通過復制現有對象創建新對象,避免直接使用new。其核心實現步驟為:1.定義抽象原型類,聲明clone()和display()純虛函數;2.創建具體原型類,實現clone()(調用拷貝構造或自定義復制邏輯);3.可選使用原型管理器注冊并克隆對象;4.客戶端通過管理器或直接調用clone()生成對象。深拷貝遞歸復制所有字段,確保獨立性;淺拷貝僅復制基本字段和指針引用,導致共享內存。為避免對象切片,需在clone()中返回派生類指針并確保多態性。原型模式側重復制,適用于大量相似對象創建;工廠模式側重封裝創建邏輯,適合復雜創建過程。兩者選擇取決于具體需求。
c++原型模式旨在通過復制現有對象來創建新對象,避免了使用 new 關鍵字的復雜性,尤其是在需要創建大量相似對象時。它就像一個“克隆工廠”,你可以定制化克隆過程。
C++原型模式的實現方式:
-
定義抽象原型類: 創建一個抽象基類,聲明一個純虛函數 clone()。這個函數負責創建對象的副本。
立即學習“C++免費學習筆記(深入)”;
#include <iostream> #include <string> class Prototype { public: virtual Prototype* clone() = 0; virtual void display() = 0; virtual ~Prototype() {} };
-
創建具體原型類: 從抽象原型類派生具體類,并實現 clone() 函數。clone() 函數通常會調用拷貝構造函數或提供自定義的復制邏輯。
class ConcretePrototype1 : public Prototype { private: std::string data; public: ConcretePrototype1(std::string data) : data(data) {} ConcretePrototype1(const ConcretePrototype1& other) : data(other.data) { std::cout << "ConcretePrototype1 copy constructor called." << std::endl; // 可選:觀察拷貝行為 } Prototype* clone() override { return new ConcretePrototype1(*this); } void display() override { std::cout << "ConcretePrototype1: " << data << std::endl; } }; class ConcretePrototype2 : public Prototype { private: int number; public: ConcretePrototype2(int number) : number(number) {} ConcretePrototype2(const ConcretePrototype2& other) : number(other.number) { std::cout << "ConcretePrototype2 copy constructor called." << std::endl; // 可選:觀察拷貝行為 } Prototype* clone() override { return new ConcretePrototype2(*this); } void display() override { std::cout << "ConcretePrototype2: " << number << std::endl; } };
-
使用原型管理器(可選): 可以創建一個原型管理器類,用于注冊和管理原型對象。這使得客戶端可以通過名稱或其他標識符來請求克隆特定類型的對象。 如果你的原型類型不多,或者創建過程很簡單,可以省略這個步驟。
#include <map> #include <memory> class PrototypeManager { private: std::map<std::string, Prototype*> prototypes; public: PrototypeManager() {} ~PrototypeManager() { for (auto const& [key, val] : prototypes) { delete val; } } void addPrototype(const std::string& key, Prototype* prototype) { prototypes[key] = prototype; } Prototype* getPrototype(const std::string& key) { auto it = prototypes.find(key); if (it != prototypes.end()) { return it->second->clone(); } return nullptr; } };
-
客戶端代碼: 客戶端代碼使用原型對象或原型管理器來創建新對象,而無需知道具體類的細節。
int main() { PrototypeManager manager; manager.addPrototype("type1", new ConcretePrototype1("Hello")); manager.addPrototype("type2", new ConcretePrototype2(123)); Prototype* object1 = manager.getPrototype("type1"); if (object1) { object1->display(); delete object1; } Prototype* object2 = manager.getPrototype("type2"); if (object2) { object2->display(); delete object2; } return 0; }
原型模式的深拷貝和淺拷貝有什么區別?
深拷貝和淺拷貝是原型模式中需要重點關注的問題。淺拷貝只復制對象的基本類型字段,對于指針或引用類型的字段,只復制指針或引用本身,而不是指向的對象。這意味著原始對象和克隆對象會共享同一塊內存,修改其中一個對象會影響另一個對象。而深拷貝會遞歸地復制所有字段,包括指針或引用指向的對象,從而創建完全獨立的副本。
在C++中,默認的拷貝構造函數和賦值運算符執行的是淺拷貝。因此,如果你的類包含指針或引用類型的成員變量,你需要自定義拷貝構造函數和賦值運算符來實現深拷貝。
如何避免原型模式中的對象切片問題?
對象切片是指在通過基類指針或引用復制派生類對象時,只復制了基類部分的數據,而派生類特有的數據被忽略的現象。這通常發生在沒有正確實現 clone() 函數的情況下。
避免對象切片的關鍵是在基類的 clone() 函數中返回派生類對象的指針。為了確保類型安全,可以使用 dynamic_cast 進行類型轉換,或者使用模板方法模式來創建克隆函數。 另外,基類的 clone() 函數需要返回基類指針類型,這樣才能保證多態性。
原型模式與工廠模式的區別是什么?
原型模式和工廠模式都是創建型設計模式,但它們的側重點不同。工廠模式主要用于封裝對象的創建過程,將對象的創建邏輯集中在一個工廠類中,客戶端只需要指定要創建的對象類型,而無需知道具體的創建細節。原型模式則通過復制現有對象來創建新對象,避免了使用 new 關鍵字的復雜性。
簡單來說,工廠模式關注的是對象的創建過程,而原型模式關注的是對象的復制過程。工廠模式通常需要定義多個工廠類來創建不同類型的對象,而原型模式只需要定義一個原型接口和具體的原型類。在選擇使用哪種模式時,需要根據具體的應用場景和需求進行權衡。如果對象的創建過程比較復雜,或者需要動態地指定要創建的對象類型,那么工廠模式可能更適合。如果對象的創建過程比較簡單,或者需要創建大量相似的對象,那么原型模式可能更適合。