【设计模式】原型模式

转换阵地,用《Mastering Python Design Patterns》来作指导。

clone()函数

# /usr/bin/python
# coding=utf-8


import copy


class A:
    def __init__(self):
        self.x = 18
        self.msg = 'Hello'


class B(A):
    def __init__(self):
        A.__init__(self)
        self.y = 34

    def __str__(self):
        return '{}, {}, {}'.format(self.x, self.msg, self.y)


if __name__ == '__main__':
    b = B()
    c = copy.deepcopy(b)
    print b
    print c
    print (b, c)
    print [i for i in str(b)]
    print [str(i) for i in (b, c)]
    print [i for i in (b, c)]
    print "%s"%c
    print "%s" % b

输出

18, Hello, 34
18, Hello, 34
(<__main__.B instance at 0x10d0edef0>, <__main__.B instance at 0x10d0edf38>)
['1', '8', ',', ' ', 'H', 'e', 'l', 'l', 'o', ',', ' ', '3', '4']
['18, Hello, 34', '18, Hello, 34']
[<__main__.B instance at 0x10d0edef0>, <__main__.B instance at 0x10d0edf38>]
18, Hello, 34
18, Hello, 34

Process finished with exit code 0
  • 方法str是一个特殊方法,它构造并返回PhoneNumber类的一个对象的字符串表示。解析器一旦遇到如下语句:
    print phone就会执行print phone.str()

  • 程序如果将PhoneNumber对象传给内建函数str(如str(phone)),或者为PhoneNumber对象使用字符串格式化运算符%(例如"%s"%phone),Python也会调用str方法

原型模式实现

当我们已有一个对象,并希望创建该对象的一个完整副本时,原型模式就派上用场了。在我们知道对象的某些部分会被变更但又希望保持原有对象不变之时,通常需要对象的一个副本。在这样的案例中,重新创建原有对象是没有意义的。
当我们想复制一个复杂对象时,使用原型模式会很方便。对于复制复杂对象,我们可以将对象当做是从数据库中获取的,并引用其他一些也是从数据库中获取的对象。若通过多次重复查询数据来创建一个对象,则要做很多的工作。在这种场景下使用原型模式要方便的多。

  • copy构造一个新的复合对象后,会尽可能地将在原始对象中找到的对象的引用插入新对象中
  • deepcopy构造一个新的复合对象后,会递归地将在原始对象中找到的对象的副本插入新对象中

两个版本的书有区别,也有大量的相似之处。如果知道两个版本的相似之处,可以先克隆一份,然后仅修改新版本与旧版本之间的不同之处。

# /usr/bin/python
# coding:utf-8

import copy
from collections import OrderedDict


class Book:
    def __init__(self, name, authors, price, **rest):
        '''rest的例子有:出版商、长度、标签、出版日期'''
        self.name = name
        self.authors = authors
        self.price = price
        self.__dict__.update(rest)

    def __str__(self):
        mylist = []
        ordered = OrderedDict(sorted(self.__dict__.items()))
        for i in ordered.keys():
            mylist.append('{}: {}'.format(i, ordered[i]))
            if i == "price":
                mylist.append('$')
            mylist.append('\n')
        return ''.join(mylist)


class Prototype:
    def __init__(self):
        self.objects = dict()

    def register(self, identifier, obj):
        self.objects[identifier] = obj

    def unregister(self, identifier):
        del self.objects[identifier]

    def clone(self, identifier, **attr):
        found = self.objects.get(identifier)
        if not found:
            raise ValueError("Incorrect object identifier: {}".format(identifier))
        obj = copy.deepcopy(found)
        obj.__dict__.update(attr)
        return obj


class main():
    b1 = Book('The C programming Language', ('Brain W. Kernighan', 'Dennis M.Ritchie'),
              price=118, publisher='Prentice Hall', length=228, publication_date='1978-02-22',
              tags=('C', 'programming', 'algorithms', 'data structures'))
    prototype = Prototype()
    cid = 'k&r-first'
    prototype.register(cid, b1)
    b2 = prototype.clone(cid, name='The C Programming Language(ANSI)', price=48.99,
                         length=274, publication_date='1988-04-01', edition=2)
    for i in (b1, b2):
        print i
    print "ID b1 : {} != ID b2 : {}".format(id(b1), id(b2))


if __name__ == "__main__":
    main()

输出

authors: ('Brain W. Kernighan', 'Dennis M.Ritchie')
length: 228
name: The C programming Language
price: 118$
publication_date: 1978-02-22
publisher: Prentice Hall
tags: ('C', 'programming', 'algorithms', 'data structures')

authors: ('Brain W. Kernighan', 'Dennis M.Ritchie')
edition: 2
length: 274
name: The C Programming Language(ANSI)
price: 48.99$
publication_date: 1988-04-01
publisher: Prentice Hall
tags: ('C', 'programming', 'algorithms', 'data structures')

ID b1 : 4340495568 != ID b2 : 4340690096

Process finished with exit code 0

你可能感兴趣的:(【设计模式】原型模式)