python 实现 原型模式

 

本文的目录地址

本文的代码地址

有时,我们需要原原本本地为对象创建一个副本。举例来说,假设你想创建一个应用来存储、分享、编辑(比如,修改、添加注释及删除)食谱。用户Bob找到一份蛋糕食谱,在做了一些改变后,觉得自己做的蛋糕非常美味,想要与朋友Alice分享这个食谱。但是该如何分享食谱呢?如果在与Alice分享之后,Bob想对食谱做进一步的试验,Alice手里的食谱也能跟着变化吗?Bob能够持有蛋糕食谱的两个副本吗?对蛋糕食谱进行的试验性变更不应该对原本美味蛋糕的食谱造成影响。

这样的问题可以通过让用户对同一份食谱持有多个独立的副本来解决。每个副本被称为一个克隆,是某个时间点原有对象的一个完全副本。这里时间是一个重要因素。因为它会影响克隆所包含的内容。例如,如果Bob在对蛋糕食谱做改进以臻完美之前就与Alice分享了,那么Alice就绝不可能像Bob那样烘烤出自己的美味蛋糕,只能按照Bob原来找到的食谱烘烤蛋糕。

注意引用与副本之间的区别。如果Bob和Alice持有的是同一个蛋糕食谱对象的两个引用,那么Bob对食谱做的任何改变,对于Alice的食谱版本都是可见的,反之亦然。我们想要的是Bob和Alice各自持有自己的副本,这样他们可以各自做变更而不会影响对方的食谱。实际上Bob需要蛋糕食谱的两个副本:美味版本和试验版本。

下图展示了引用与副本之间的区别。

原型设计模式(Prototype design pattern)帮助我们创建对象的克隆,其最简单的形式就是一个clone()函数,接受一个对象作为输入参数,返回输入对象的一个副本。在Python中,这可以使用copy.deepcopy()函数来完成。来看一个例子,下面的代码中(文件clone.py)有两个类,A和B。A是父类,B是衍生类/子类。在主程序部分,我们创建一个类B的实例b,并使用deepcopy()创建b的一个克隆c。结果是所有成员都被复制到了克隆c,以下是代码演示。

import copy


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


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

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


if __name__ == '__main__':
    b = B()
    c = copy.deepcopy(b)
    print([str(i) for i in (b, c)])
    print([(i, i.A) for i in (b, c)])
#Output:
# ['18, Hello, 34', '18, Hello, 34']
# [(<__main__.B object at 0x7f0dc45c0710>, <__main__.A object at 0x7f0dc45f9588>), (<__main__.B object at 0x7f0dc465efd0>, <__main__.A object at 0x7f0dc45f9588>)]

虽然你得到的第二行输出很可能与我的不一样,但重要的是注意两个对象位于两个不同的内存地址(输出中的0x...部分)。这意味着两个对象是两个独立的副本。

在1.2节,我们将看到为了保持一个被克隆对象的注册表,如何将copy.deepcopy与封装在某个类中的一些额外的样板代码一起使用。

目录

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值