設計模式(六)——原型模式
設計模式(六)——原型模式
一、原型模式簡介
1、原型模式簡介
原型模式使用原型實例指定創建對象的種類,並且通過拷貝原型對象創建新的對象。
Prototype模式提供了一個通過已存在對象進行新對象創建的接口(clone), clone()實現和具體的語言相關,在C++中通過拷貝構造函數實現。
原型模式實際上就是從一個對象再創建另外一個可定制的對象,而且不需要知道任何創建的細節。在初始化的信息不發生變化的情況下,克隆是最好的辦法,既隱藏了對象創建的細節,又大大提高了性能。因為如果不用clone,每次new都需要執行一次構造函數,如果構造函數的執行時間很長,那麽多次的執行初始化操作就太低效了。
原型模式實現clone接口的時候必須使用深拷貝。
原型模式重點在從自身賦值自己創建新的類對象,隱藏創建的細節。
2、原型模式角色
抽象原型(Prototype)角色:規定了具體原型對象必須實現的接口(如果要提供深拷貝,則必須具有實現clone的規定)
具體原型(ConcretePrototype):從抽象原型派生而來,是客戶程序使用的對象,即被復制的對象
客戶(Client)角色:使用原型對象的客戶程序
3、原型模式優缺點
優點:
A、原型模式對客戶隱藏了具體的產品類
B、運行時刻增加和刪除產品: 原型模式允許只通過客戶註冊原型實例就可以將一個新的具體產品類並入系統。
C、改變值以指定新對象: 高度動態的系統允許通過對象復合定義新的行為。如通過為一個對象變量指定值並且不定義新的類。通過實例化已有類並且將實例註冊為客戶對象的原型,就可以有效定義新類別的對象。客戶可以將職責代理給原型,從而表現出新的行為。
D、改變結構以指定新對象:許多應用由部件和子部件來創建對象。
E、減少子類的構造
F、用類動態配置應用 一些運行時刻環境允許動態將類裝載到應用中。
G、使用原型模式創建對象比直接new一個對象在性能上要好的多,因為Object類的clone方法是一個本地方法,直接操作內存中的二進制流,特別是復制大對象時,性能的差別非常明顯。
H、使用原型模式的另一個好處是簡化對象的創建,使得創建對象很簡單。
缺點:
原型模式的主要缺陷是每一個抽象原型Prototype的子類都必須實現clone操作,實現clone函數可能會很困難。當所考慮的類已經存在時就難以新增clone操作,當內部包括一些不支持拷貝或有循環引用的對象時,實現克隆可能也會很困難的。
4、原型模式使用場景
原型模式的主要思想是基於現有的對象克隆一個新的對象出來,一般是由對象的內部提供克隆的方法,通過clone方法返回一個對象的副本。
原型模式使用場景:
A、當一個系統應該獨立於它的產品創建、構成和表示時,要使用原型模式
B、當要實例化的類是在運行時刻指定時,如通過動態裝載
C、為了避免創建一個與產品類層次平行的工廠類層次時
D、當一個類的實例只能有幾個不同狀態組合中的一種時。建立相應數目的原型並克隆原型可能比每次用合適的狀態手工實例化原型類更方便一些。
5、淺拷貝與深拷貝
A、淺拷貝
被拷貝對象的所有變量都含有與原對象相同的值,而且對其他對象的引用仍然是指向原來的對象。即淺拷貝只負責當前對象實例,對引用的對象不做拷貝。
B、深拷貝
被拷貝對象的所有的變量都含有與原來對象相同的值,除了引用其他對象的變量。引用其他對象的變量將指向一個被拷貝的新對象,而不再是原有被引用對象。即深拷貝把要拷貝的對象所引用的對象也都拷貝了一次。
深拷貝要深入到多少層,是一個不確定的問題。在決定以深拷貝的方式拷貝一個對象的時候,必須決定對間接拷貝的對象是采取淺拷貝還是深拷貝還是繼續采用深拷貝。因此,在采取深拷貝時,需要決定多深才算深。此外,在深拷貝的過程中,很可能會出現循環引用的問題。
二、原型模式實現
Prototype原型基類:
#ifndef PROTOTYPE_H
#define PROTOTYPE_H
#include <iostream>
//Prototype原型基類,定義Clone接口函數
class Prototype
{
public:
//定義clone接口,根據不同的派生類來實例化對象
virtual Prototype* clone() const = 0;
virtual ~Prototype()
{
std::cout << "Prototype::~Prototype()" << std::endl;
}
protected:
Prototype()
{
std::cout << "Prototype::Prototype()" << std::endl;
}
};
#endif // PROTOTYPE_H
ConcretePrototypeA原型派生類:
#ifndef CONCRETEPROTOTYPEA_H
#define CONCRETEPROTOTYPEA_H
#include "Prototype.h"
//派生自Prototype,實現其接口函數
class ConcretePrototypeA : public Prototype
{
public:
ConcretePrototypeA()
{
std::cout << "ConcretePrototypeA::ConcretePrototypeA()" << std::endl;
}
~ConcretePrototypeA()
{
std::cout << "ConcretePrototypeA::~ConcretePrototypeA()" << std::endl;
}
//拷貝構造函數
ConcretePrototypeA(const ConcretePrototypeA&)
{
std::cout << "ConcretePrototypeA::ConcretePrototypeA(const ConcretePrototypeA&)" << std::endl;
}
//實現基類定義的Clone接口,內部調用拷貝構造函數實現復制功能
virtual ConcretePrototypeA* clone() const
{
return new ConcretePrototypeA(*this);
}
};
#endif // CONCRETEPROTOTYPEA_H
ConcretePrototypeB原型派生類:
#ifndef CONCRETEPROTOTYPEB_H
#define CONCRETEPROTOTYPEB_H
#include "Prototype.h"
//派生自Prototype,實現其接口函數
class ConcretePrototypeB : public Prototype
{
public:
ConcretePrototypeB()
{
std::cout << "ConcretePrototypeB::ConcretePrototypeB()" << std::endl;
}
~ConcretePrototypeB()
{
std::cout << "ConcretePrototypeB::~ConcretePrototypeB()" << std::endl;
}
//拷貝構造函數
ConcretePrototypeB(const ConcretePrototypeB&)
{
std::cout << "ConcretePrototypeB::ConcretePrototypeB(const ConcretePrototypeB&)" << std::endl;
}
//實現基類定義的Clone接口,內部調用拷貝構造函數實現復制功能
virtual ConcretePrototypeB* clone() const
{
return new ConcretePrototypeB(*this);
}
};
#endif // CONCRETEPROTOTYPEB_H
客戶調用程序:
#include "Prototype.h"
#include "ConcretePrototypeA.h"
#include "ConcretePrototypeB.h"
int main()
{
Prototype* p1 = new ConcretePrototypeA();
Prototype* p2 = p1->clone();
Prototype* p3 = new ConcretePrototypeA();
Prototype* p4 = p3->clone();
delete p1;
delete p2;
delete p3;
delete p4;
return 0;
}
本文出自 “生命不息,奮鬥不止” 博客,謝絕轉載!
設計模式(六)——原型模式