PythonでPrototypeパターン

Prototypeパターンではあるオブジェクトをコピーすることで新しいオブジェクトを作成する.
実装するには,属性値をコピーして新しいオブジェクトを返すメソッドを定義する.

#!/usr/bin/python

class Prototype(object):
    def __init__(self, prototype = None):
        if prototype:
            self.value = prototype.getValue();
        else:
            self.value = 0;
    def increment(self):
        self.value += 1;
    def getValue(self):
        return self.value;
    def clone(self):
        return Prototype(self);

class PrototypeA(Prototype):
    def __init__(self, prototype = None):
        Prototype.__init__(self, prototype);
        self.value = 0.0;

if __name__ == '__main__':
    a = Prototype();
    print "a.getValue() = " + str(a.getValue());
    a.increment();
    print "a.getValue() = " + str(a.getValue());
    b = a.clone();
    print "b.getValue() = " + str(b.getValue());

    c = PrototypeA();
    c.increment();
    print "c.getValue() = " + str(c.getValue());
    d = c.clone();
    print "d.getValue() = " + str(d.getValue());

    c.increment();
    print "c.getValue() = " + str(c.getValue());
    print "d.getValue() = " + str(d.getValue());

実行結果.b, dはともにa, cをプロトタイプとして作成されたオブジェクト.当然それぞれ独立して属性値を変更できる.

a.getValue() = 0
a.getValue() = 1
b.getValue() = 1    ← aをコピーしてbが作られている.だから値も一緒
c.getValue() = 1.0
d.getValue() = 1.0  ← cをコピーしてbが作られている.だから値も一緒
c.getValue() = 2.0  ← c.increment()を呼び出す.よってc.getValue()は2.0を返す
d.getValue() = 1.0  ← dとcは別のオブジェクトのため,c.increment()はdの状態に影響を与えない

今は単純なオブジェクトだったので考えなくても良かったが,属性値がオブジェクトだった場合,そのオブジェクトもコピーしなくてはならないと思われる.

作ってから調べたら,Pythonには浅い/深いコピーを実現するライブラリがあるようだ:3.18 copy -- 浅いコピーおよび深いコピー操作.これを使うともっと簡単に実現できる.

import copy;

class Prototype(object):
    def __init__(self):
        self.value = 0;
    def increment(self):
        self.value += 1;
    def getValue(self):
        return self.value;
    def clone(self):
        return copy.deepcopy(self);

class PrototypeA(Prototype):
    def __init__(self):
        self.value = 0.0;