1. 程式人生 > >設計模式---對象創建模式之原型模式(prototype)

設計模式---對象創建模式之原型模式(prototype)

col 具體類 不同 new mark out 初始化 isp clas

一:概念

原型模式(Prototype Pattern)  實際上就是動態抽取當前對象運行時的狀態
Prototype模式是一種對象創建型模式,它采取復制原型對象的方法來創建對象的實例。使用Prototype模式創建的實例,具有與原型一樣的數據。

1)由原型對象自身創建目標對象。也就是說,對象創建這一動作發自原型對象本身。

2)目標對象是原型對象的一個克隆。也就是說,通過Prototype模式創建的對象,不僅僅與原型對象具有相同的結構,還與原型對象具有相同的值。

3)根據對象克隆深度層次的不同,有淺度克隆與深度克隆。
適用情況: 一個復雜對象,具有自我復制功能,統一一套接口。 對於對象比較復雜,每創建一次new 都會浪費好多的資源和時間 且在初始化的信息不發生變化的前提下 克隆是最好的辦法,

二:動機

在軟件系統中,經常面臨著“某些結構復雜的對象”的創建工作;由於需求的變化,這些對象經常面臨著劇烈的變化,但是他們卻擁有著比較穩定一致的接口。
如何應對這種變化?如何向“客戶程序(使用這些對象的程序)”隔離出“這些易變對象”,從而使得“依賴這些易變對象的客戶程序”不隨著需求改變而改變?
原型模式也是屬於對象創建模式,它用來處理某些結構復雜對象的創建工作,這也是與工廠模式最大的區別。
如果我們要創建的對象比較簡單的話,使用工廠模式new一下就可以了,但是當對象比較復雜,它的初始狀態不是我們最想用的時候,我們可以調用拷貝構造函數來深拷貝
某個比較符合我們要求的對象。當然所謂的復雜是相對而言的,應當根據實際情況確定。

三:代碼講解

(一)原代碼

//抽象類
class ISplitter{
public:
    virtual void split()=0;
    virtual ~ISplitter(){}
};


//工廠基類
class SplitterFactory{
public:
    virtual ISplitter* CreateSplitter()=0;
    virtual ~SplitterFactory(){}
};
技術分享圖片
//具體類
class BinarySplitter : public
ISplitter{ }; class TxtSplitter: public ISplitter{ }; class PictureSplitter: public ISplitter{ }; class VideoSplitter: public ISplitter{ }; //具體工廠 class BinarySplitterFactory: public SplitterFactory{ public: virtual ISplitter* CreateSplitter(){ return new BinarySplitter(); } }; class TxtSplitterFactory: public SplitterFactory{ public: virtual ISplitter* CreateSplitter(){ return new TxtSplitter(); } }; class PictureSplitterFactory: public SplitterFactory{ public: virtual ISplitter* CreateSplitter(){ return new PictureSplitter(); } }; class VideoSplitterFactory: public SplitterFactory{ public: virtual ISplitter* CreateSplitter(){ return new VideoSplitter(); } };
具體類和具體工廠

(二)原型模式處理:將兩個類合並

1.將抽象類和抽象工廠合並

//抽象類
class ISplitter{
public:
    virtual void split()=0;
    //通過克隆自己來創建對象
    virtual ISplitter* clone()=0;    //CreateSplitter
    
    virtual ~ISplitter(){}

};

2.將具體類和具體工廠合並

class BinarySplitter : public ISplitter{  //由原來的具體類和具體工廠合並
public:
    virtual ISplitter* clone(){
        return new BinarySplitter(*this);  //深拷貝,將原有狀態一並拷貝過去
    }
};
class TxtSplitter: public ISplitter{
public:
    virtual ISplitter* clone(){
        return new TxtSplitter(*this);
    }
};

class PictureSplitter: public ISplitter{
public:
    virtual ISplitter* clone(){
        return new PictureSplitter(*this);
    }
};

class VideoSplitter: public ISplitter{
public:
    virtual ISplitter* clone(){
        return new VideoSplitter(*this);
    }
};

(三)MainForm中使用

class MainForm : public Form
{
    Isplitter*  prototype;//原型對象

public:
    
    MainForm(Isplitter*  prototype){
        this->prototype=prototype;
    }
    
    void Button1_Click(){
        //prototype->split;    不能直接使用,原型對象是專門供你克隆的,真正使用的時候,我們要使用新的對象
        
        ISplitter * splitter=
            prototype->clone(); //克隆原型
        
        splitter->split();
    }
};

四:模式定義

使用原型實例指定創建對象的種類,然後通過拷貝這些原型來創建新的對象。 

                                                               --《設計模式》Gof

五:類圖(結構)

技術分享圖片

六:使用場景:和工廠相比

(一)當某一個對象比較復雜的時候,通常你發現他的初始狀態不是最理想的,這時候有一個對象,他的狀態已經達到比較好的狀態的時候,我們調用一下拷貝構造函數(深克隆),將他的狀態取出來,這樣就達到了一個比較好的狀態。

(二)而我們使用工廠模式,我們創建一個新的對象,當對象結構復雜,我們new一個新的對象後,往往需要大量的操作去達到一個較好的狀態,不夠靈活,所以工廠模式適用於結構不太復雜的對象。

(三)二者區別在於是否有較復雜的中間狀態,而且是否希望保留某個狀態

(四)一個復雜對象,具有自我復制功能,統一一套接口

七:要點總結

(一)Prototype模式同樣用於隔離類對象的使用者和具體類型(易變類)直接的耦合關系,他同樣要求這些“易變類”擁有“穩定的接口”。

(二)Prototype模式對於“如何創建易變類的實體對象”采用“原型克隆”的方法來做,它使得我們可以非常靈活地“動態創建”擁有某些穩定接口的新對象——所需工作僅僅是註冊一個新類的對象(即原型),然後在任何需要的地方clone。

(三)Prototype模式中的Clone方法可以利用某些框架中的序列化來實現深拷貝。

像python中pickle

八:案例實現

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <stdlib.h>
#include <string>  //需要加上string,不然cout<<string對象會報錯
using namespace std;


class Programmer
{
public:
    virtual Programmer* clone() = 0;  //接口
    virtual void printInfo() = 0;
    virtual void setJob(char *job) = 0;
    virtual ~Programmer(){}
};

class JavaProgrammer :public Programmer
{
private:
    string name;
    int age;
    char* job;
public:
    JavaProgrammer(string name, int age)
    {
        this->name = name;
        this->age = age;
        job = NULL;
    }

    virtual void setJob(char *job)
    {
        this->job = new char[strlen(job) + 1];
        strcpy(this->job, job);
    }

    virtual void printInfo()
    {
        cout << this->name << "\t" << this->age << endl;
        if (this->job)
            cout << this->job << endl;
    }

    virtual Programmer* clone()
    {
        Programmer* p = new JavaProgrammer(*this);  //對其中指針,只是賦值,指向同一塊空間
        p->setJob(this->job);  //註意這一步,要做到深拷貝
        return p;
    }

    virtual ~JavaProgrammer()
    {
        if (this->job!=NULL)
        {
            delete[] this->job;
            this->job = NULL;
        }
    }
};

void main()
{
    JavaProgrammer jv1("Mark", 20);
    jv1.setJob("java programmer");
    jv1.printInfo();
    Programmer* np = jv1.clone();
    np->printInfo();

    delete np;  //保錯是因為拷貝問題

    system("pause");
    return;
}

技術分享圖片

模擬狀態,我們不對原型對象進行修改

設計模式---對象創建模式之原型模式(prototype)