Skeleton of GOF's Design Pattern


PROTOTYPEの骸骨

PROTOTYPE

自分自身の複製(クローン)を作成するのがこのパターンです。

このクラスの利点は、抽象クラスだけを扱うクライアントが、そのクラスの具象クラスを知ることなく、属性を引き継いだ新たなクラスを生成することができるという点です。

PROTOTYPE は、仮想コピーコンストラクタと呼ばれます。C++では、コピーコンストラクタは仮想関数にすることができませんが、PROTOTYPE を使えば、抽象クラスからコピーコンストラクタを呼ぶことができます。仮想コンストラクタについては、FACTORYMETHOD を参照してください。


■ 『PROTOTYPEの骸骨』の構造


■ 『PROTOTYPEの骸骨』 プログラム・コード

□ Java2版
// Copyright(C) 2000-2003 Yoshinori Oota All rights reserved.

public class PrototypeSample { 
    static Prototype Create(char sw) {
        if (sw == 'A') {
            return new PrototypeA();
        } else if (sw == 'B') {
            return new PrototypeB();
        }
        return null;
    }
    static public void main(String[] args) { 
        Prototype prototype = Create('A');
        prototype.Operation("Hello");        // 値を変えてみる
        Prototype clone = prototype.Clone();
        clone.Operation();                   // 属性が引き継がれました。

        prototype = Create('B');
        prototype.Operation("1234");
        clone = prototype.Clone();
        clone.Operation();
    }
}


abstract class Prototype {
    abstract public Prototype Clone();
    abstract public void Operation(String str);
    abstract public void Operation();
}

class PrototypeA extends Prototype {
    private String _value = "";
    public PrototypeA();
    public PrototypeA(PrototypeA p) {
        _value = p._value;
    } 
    public void Operation(String str) { 
        _value = str;
        System.out.println("update PrototypeA::_value to " + _value);
    }
    public void Operation() {
        System.out.println("PrototypeA::_value is " + _value);      
    }
    public Prototype Clone() { 
       return new PrototypeA(this); 
    }
}
class PrototypeB extends Prototype {
    private Integer _value = new Integer(-1);
    public PrototypeB();
    public PrototypeB(PrototypeB p) {
        _value = p._value;
    } 
    public void Operation(String str) {
        _value = Integer.decode(str);
        System.out.println("update PrototypeB::_value to " + _value);
    }
    public void Operation() {
        System.out.println("PrototypeB::_value is " + _value);      
    }
    public Prototype Clone() { 
       return new PrototypeB(this); 
    }
}

○ C++版
// Copyright(C) 2003 Yoshinori Oota All rights reserved.

#include <cstring>
#include <iostream>
using namespace std;

class Prototype {
public:
    Prototype();
    virtual ~Prototype();
    virtual Prototype* Clone() = 0;
    virtual void Operation(const string& str) = 0;
    virtual void Operation() const = 0;
};

class PrototypeA : public Prototype {
public:
    PrototypeA();
    PrototypeA(const PrototypeA& p);
    virtual ~PrototypeA();
    virtual Prototype* Clone();
    virtual void Operation(const string& str);
    virtual void Operation() const;
private:
    string value_;
};

class PrototypeB : public Prototype {
public:
    PrototypeB();
    PrototypeB(const PrototypeB& p);
    virtual ~PrototypeB();
    virtual Prototype* Clone();
    virtual void Operation(const string& str);
    virtual void Operation() const;
private:
    int value_;
};


Prototype::Prototype() { }
Prototype::~Prototype() { }

PrototypeA::PrototypeA() : value_("") { }
PrototypeA::PrototypeA(const PrototypeA& p) : value_(p.value_) { }
PrototypeA::~PrototypeA() { }
Prototype* PrototypeA::Clone() {
    return new PrototypeA(*this);
}
void PrototypeA::Operation(const string& str) {
    value_ = str;
    cout << "update PrototypeA::value_ to " << value_ << endl;
}
void PrototypeA::Operation() const {
    cout << "PrototypeA::value_ is " << value_ << endl;
}

PrototypeB::PrototypeB() : value_(-1) { }
PrototypeB::PrototypeB(const PrototypeB& p) : value_(p.value_) { }
PrototypeB::~PrototypeB() { }
Prototype* PrototypeB::Clone() {
    return new PrototypeB(*this);
}
void PrototypeB::Operation(const string& str) {
    value_ = atoi(str.c_str());
    cout << "update PrototypeB::value_ to " << value_ << endl;
}
void PrototypeB::Operation() const {
    cout << "PrototypeB::value_ is " << value_ << endl;
}


Prototype* Create(char sw) {
    if (sw == 'A') {
        return new PrototypeA();
    } else if (sw == 'B') {
        return new PrototypeB();
    }
}

int main() {
    Prototype* prototype = Create('A');
    prototype->Operation("Hello");
    Prototype* clone = prototype->Clone();
    clone->Operation();
    delete prototype;
    delete clone;

    prototype = Create('B');
    prototype->Operation("1234");
    clone = prototype->Clone();
    clone->Operation();
    delete prototype;
    delete clone;

    return 0;
}

○ C版
/* Copyright(C) 2009 Yoshinori Oota All rights reserved. */
#include <stdio.h>
#include <stdlib.h>
enum CLASS_TYPE { CLASS_A ,CLASS_B };

/* Prototype Interface */
struct Prototype {
    enum CLASS_TYPE type_;
    char* value_a_; /* PrototypA用のメンバー変数 */
    int value_b_; /* PrototypB用のメンバー変数 */ 
    void (*Operation)(struct Prototype* pthis ,const char* value);
    void (*Print)(struct Prototype* pthis);
    struct Prototype* (*Clone)(struct Prototype* pthis);
};
struct Prototype* New_Prototype(enum CLASS_TYPE type);
struct Prototype* New_PrototypeA(const char* value);
struct Prototype* New_PrototypeB(int value);
void Delete_Prototype(struct Prototype* prototype);
void PrototypeA_Operation(struct Prototype* pthis ,const char* value);
void PrototypeB_Operation(struct Prototype* pthis ,const char* value);
void PrototypeA_Print(struct Prototype* pthis);
void PrototypeB_Print(struct Prototype* pthis);
struct Prototype* PrototypeA_Clone(struct Prototype* pthis);
struct Prototype* PrototypeB_Clone(struct Prototype* pthis);

/* Prototype Class Implementation */
struct Prototype* New_Prototype(enum CLASS_TYPE type) {
    struct Prototype* prototype = NULL;
    char* buf = NULL;
    prototype = (struct Prototype*)malloc(sizeof(struct Prototype));
    prototype->type_ = type;
    buf = (char*)malloc(2);
    strcpy(buf, " ");
    /* 初期化には派生クラスを意識しなければならない */
    prototype->value_a_ = buf;
    prototype->value_b_ = -1;
    switch(type) {
    case CLASS_A:
        prototype->Operation = &PrototypeA_Operation;
        prototype->Print = &PrototypeA_Print;
        prototype->Clone = &PrototypeA_Clone;
        break;
    case CLASS_B:
        prototype->Operation = &PrototypeB_Operation;
        prototype->Print = &PrototypeB_Print;
        prototype->Clone = &PrototypeB_Clone;
        break;
    }
    return prototype;
}

struct Prototype* New_PrototypeA(const char* value) {
    struct Prototype* prototype = NULL;
    char* buf = NULL;
    buf = (char*)malloc(strlen(value)+1);
    strcpy(buf, value);
    prototype = New_Prototype(CLASS_A);
    prototype->value_a_ = buf;
    return prototype;
}

struct Prototype* New_PrototypeB(int value) {
    struct Prototype* prototype = NULL;
    prototype = New_Prototype(CLASS_B);
    prototype->value_b_ = value;
    return prototype;
}

void Delete_Prototype (struct Prototype* prototype) {
    if (prototype == NULL) {
        return;
    }
    switch(prototype->type_) {
    case CLASS_A:
        free(prototype);
        prototype = NULL;
        return;
    case CLASS_B:
        if (prototype->value_a_ != NULL) {
            free(prototype->value_a_);
            prototype->value_a_ = NULL;
        }
        free(prototype);
        prototype = NULL;
        return;
    }
    return;
}

void PrototypeA_Operation (struct Prototype* pthis ,const char* value) {
    char* buf = NULL;
    buf = (char*)malloc(strlen(value)+1);
    strcpy(buf, value);
    if (pthis->value_a_ != NULL) {
        free(pthis->value_a_);
    }
    pthis->value_a_ = buf;
    printf("update PrototypeA::value_ to %s\n",pthis->value_a_); 
    return;
}

void PrototypeB_Operation (struct Prototype* pthis , const char* value) {
    int n = 0;
    n = atoi(value);
    pthis->value_b_ = n;
    printf("update PrototypeB::value_ to %d\n",pthis->value_b_); 
    return;
}

struct Prototype* PrototypeA_Clone (struct Prototype* pthis) {
    return New_PrototypeA(pthis->value_a_);
}

struct Prototype* PrototypeB_Clone (struct Prototype* pthis) {
    return New_PrototypeB(pthis->value_b_);
}

void PrototypeA_Print (struct Prototype* pthis)  {
    printf("PrototypeA::value_ is %s\n", pthis->value_a_);
    return;
}

void PrototypeB_Print (struct Prototype* pthis)  {
    printf("PrototypeB::value_ is %d\n", pthis->value_b_);
    return;
}

struct Prototype* Create(char sw) {
    if (sw == 'A') {
        return New_Prototype(CLASS_A);
    } else if (sw == 'B') {
        return New_Prototype(CLASS_B);
    }
    return NULL;
}

int main() {
    struct Prototype* prototype = NULL;
    struct Prototype* clone = NULL;

    prototype = Create('A');
    prototype->Operation(prototype, "Hello");
    clone = prototype->Clone(prototype);
    clone->Print(clone);
    Delete_Prototype(prototype);
    Delete_Prototype(clone);

    prototype = Create('B');
    prototype->Operation(prototype, "1234");
    clone = prototype->Clone(prototype);
    clone->Print(clone);
    Delete_Prototype(prototype);
    Delete_Prototype(clone);

    return 0;
}


改訂履歴

2009.2.21 C言語版を追加
     
     

ご意見、ご感想はこちらまで。

Copyright(C) 2000-2009 Yoshinori Oota All rights reserved.

本ホームページのリンクは自由です。複製、転載される場合は、必ず著者までご連絡をください。