创建型设计模式-原型模式(prototype)- python实现

设计模式汇总:查看

通俗示例

想象一下,你正在制作一个复杂的文档,这个文档包含了大量的文本、图片和格式设置。现在,你希望创建一个与当前文档内容完全相同的新文档,但又不希望花费时间重新编辑和排版。在这个时候,如果有一个“复制”按钮,你可以一键复制整个文档,并在新的副本上进行修改,这该多方便啊!这个“复制”按钮就是原型模式的现实例子。

通俗解释

原型模式是一种创建型设计模式,它允许我们通过复制现有的对象来创建新的对象,而不是通过传统的构造函数创建。这种模式特别适用于创建复杂对象时,可以避免初始化的复杂性,提高效率。

在原型模式中,我们有一个原型接口,它定义了复制自身的方法。具体原型类会实现这个接口,并提供复制自身的具体逻辑。当客户端需要创建一个新对象时,它不是直接实例化一个新对象,而是向一个原型对象请求一个复制自身的方法,从而获得一个新的对象。

原型模式的组成

  • 抽象原型(Prototype):这是一个接口,用来声明复制自身的方法。
  • 具体原型(Concrete Prototype):实现了抽象原型的接口,提供复制自身的具体实现。
  • 客户端(Client):通过调用原型对象的复制方法来创建新的对象。

原型模式的两种复制方式

  • 浅复制:只复制对象本身及其包含的值类型的成员变量,而对于引用类型的成员变量,浅复制会复制引用,不会复制引用指向的对象。
  • 深复制:除了复制对象本身及其包含的值类型的成员变量外,还会复制引用类型的成员变量所指向的对象。

Python代码示例

下面是一个简单的原型模式实现示例

"""
比如:当我们出版了一本书《Python 设计模式 1.0版》,
若10 年后我们觉得这本书跟不上时代了,这时候需要去重写一本《Python 设计模式 2.0版》,
那么我们是完全重写一本书呢?还是在原有《Python 设计模式 1.0版》的基础上进行修改呢?
当然是后者,这样会省去很多排版、添加原有知识等已经做过的工作。
"""
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):
        # 根据 identifier 在原型列表中查找原型对象并克隆
        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


def main():
    """
    主函数,用于演示克隆技术的使用。
    它创建了一本书的对象,并使用原型模式克隆了这本书的对象,修改了某些属性。
    最后,打印出两个对象的信息和它们的内存地址,以证明它们是独立的对象。
    """
    # 创建一本书的对象,初始化各种属性,如标题、作者、价格等
    b1 = Book('The C Programming Language', ('Brian 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()
    # 注册b1对象为原型,使用一个唯一标识符进行标记
    cid = 'k&r-first'
    prototype.register(cid, b1)
    # 使用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()

更符合python方式实现,deepcopy

def pythonic_main():
    b1 = Book('The C Programming Language',
              ('Brian W. Kernighan', 'Dennis M.Ritchie'),
              price=118,
              publisher='Prentice Hall',
              length=228,
              publication_date='1978-02-22',
              tags=('C', 'programming', 'algorithms', 'data structures'))

    # 这里我们彻底抛弃之前的原型设计模式的写法
    b2 = copy.deepcopy(b1)
    b2.name = 'The C Programming Language(ANSI)'
    b2.price = 48.99
    b2.length = 274
    b2.publication_date = '1988-04-01'
    b2.edition = 2

    for i in (b1, b2):
        print(i)
    print("ID b1 : {} != ID b2 : {}".format(id(b1), id(b2)))

总结

原型模式在处理复杂对象的复制时非常有用,它简化了对象的创建过程,并允许动态地改变对象的状态。不过,使用原型模式时,需要注意深复制和浅复制的区别,以及可能出现的循环引用问题。

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