一、關(guān)于原型模式的解釋:
原型模式是一種創(chuàng)建型設(shè)計(jì)模式, 使你能夠復(fù)制已有對(duì)象, 而又無(wú)需使代碼依賴它們所屬的類。
二、理解:
問(wèn)題:如果你有一個(gè)對(duì)象, 并希望生成與其完全相同的一個(gè)復(fù)制品, 你該如何實(shí)現(xiàn)呢? 首先, 你必須新建一個(gè)屬于相同類的對(duì)象。 然后, 你必須遍歷原始對(duì)象的所有成員變量, 并將成員變量值復(fù)制到新對(duì)象中。
不錯(cuò)! 但有個(gè)小問(wèn)題。 并非所有對(duì)象都能通過(guò)這種方式進(jìn)行復(fù)制, 因?yàn)橛行?duì)象可能擁有私有成員變量, 它們?cè)趯?duì)象本身以外是不可見(jiàn)的。
直接復(fù)制還有另外一個(gè)問(wèn)題。 因?yàn)槟惚仨氈缹?duì)象所屬的類才能創(chuàng)建復(fù)制品, 所以代碼必須依賴該類。 即使你可以接受額外的依賴性, 那還有另外一個(gè)問(wèn)題: 有時(shí)你只知道對(duì)象所實(shí)現(xiàn)的接口, 而不知道其所屬的具體類, 比如可向方法的某個(gè)參數(shù)傳入實(shí)現(xiàn)了某個(gè)接口的任何對(duì)象。
解決方法:原型模式將克隆過(guò)程委派給被克隆的實(shí)際對(duì)象。 模式為所有支持克隆的對(duì)象聲明了一個(gè)通用接口, 該接口讓你能夠克隆對(duì)象, 同時(shí)又無(wú)需將代碼和對(duì)象所屬類耦合。 通常情況下, 這樣的接口中僅包含一個(gè) 克隆方法。
所有的類對(duì) 克隆方法的實(shí)現(xiàn)都非常相似。 該方法會(huì)創(chuàng)建一個(gè)當(dāng)前類的對(duì)象, 然后將原始對(duì)象所有的成員變量值復(fù)制到新建的類中。 你甚至可以復(fù)制私有成員變量, 因?yàn)榻^大部分編程語(yǔ)言都允許對(duì)象訪問(wèn)其同類對(duì)象的私有成員變量。
支持克隆的對(duì)象即為原型。 當(dāng)你的對(duì)象有幾十個(gè)成員變量和幾百種類型時(shí), 對(duì)其進(jìn)行克隆甚至可以代替子類的構(gòu)造。
所以原型模式的核心在于:實(shí)現(xiàn)類自身的clone方法,供外部使用,以達(dá)到快速和精準(zhǔn)的復(fù)制。
參考:https://refactoringguru.cn/design-patterns/prototype
三、代碼實(shí)現(xiàn)
先看一段實(shí)現(xiàn)類克隆自身的代碼
#include <iostream>
using namespace std;
class A
{
private:
int a_value;
public:
A(){};
A(int value): a_value(value){};
~A(){};
A* clone(){return new A(*this);}; // 調(diào)用類隱藏的默認(rèn)拷貝構(gòu)造函數(shù) A(const A&)
int getValue(){return a_value;};
};
int main(int argc, char **argv){
A *a1 = new A(10);
cout << a1 << " " << a1->getValue() << endl;
A *a2 = a1->clone();
cout << a2 << " " << a2->getValue() << endl;
return 0;
}
運(yùn)行結(jié)果為:
0xee7228 10
0xee8240 10
可以看出,a2是獨(dú)立于a1的對(duì)象,而且a2的私有變量a_value的數(shù)值與a1完全一致,a2是a1的完全克隆體,僅僅通過(guò)調(diào)用類對(duì)象的無(wú)參方法clone()實(shí)現(xiàn)了目的。
原型模型實(shí)現(xiàn):現(xiàn)在假設(shè)有一個(gè)抽象基類A,克隆函數(shù)clone()為純虛函數(shù), 類B,和類C均繼承自類A, 并分別實(shí)現(xiàn)自己的虛函數(shù)clone()。則有:
A *a1 = new B();
A *a2 = a1->clone(); // a1<=> a2
A *a3 = new C();
A *a4 = a3->clone(); // a3<=> a4