[Python] 设计模式之简单理解原型模式

什么是原型模式?

原型模式,就是“克隆”对象。

当一个现有对象需要保持不变,而我们想创建它的精确副本,以便更改副本的某些部分时,原型模式非常有用。

Python中的原型模式

Python天然就有使用原型模式的优势,使用copy.deepcopy()就能实现对象的完全复制(深拷贝)。

import copy
obj1 = object()
obj2 = copy.deepcopy(obj1)
print(id(obj1), id(obj2))	# 输出的两个对象的id是不一样的

原型模式示例

我们有一个Website类,用于保存网站所有有用的信息,如名称、域名、描述、我们管理的网站的作者,等等。我们每次建立新的网站而想修改所有信息时,可以在之前网站的基础上建立副本。

import copy

class Website:
    def __init__(self, name, domain, description, author, **kwargs):
        self.name, self.domain, self.description, self.author = name, domain, description, author
        for key in kwargs:
            setattr(self, key, kwargs[key])

    def __str__(self):
        infos = vars(self).items()
        return '\n'.join([f'{k}:{v}' for k, v in infos])

class Prototype:
    def __init__(self):
        print("__init__() be call!")
        self.objects = dict()

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

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

    def clone(self, obj_id, **attrs):
        old_obj = self.objects.get(obj_id)
        if not old_obj:
            raise ValueError(f'Incorrect object identifier: {obj_id}')
        new_obj = copy.deepcopy(old_obj)
        for key in attrs:
            setattr(new_obj, key, attrs[key])
        return new_obj

if __name__ == '__main__':
    site_id = 'qq'
    site_1 = Website(name='website1',domain='spade.com', description='apps store', author='spade', used='True')
    prototype = Prototype()
    prototype.register(site_id, site_1)
    site_2 = prototype.clone(site_id, name='qq', domain='qq.com', description='qq', boss='mahuateng')
    print(site_1)
    print(id(site_1))
    print()
    print(site_2)
    print(id(site_2))

输出结果:

__init__() be call!
name:website1
domain:spade.com
description:apps store
author:spade
used:True
2293159517832

name:qq
domain:qq.com
description:qq
author:spade
used:True
boss:mahuateng
2293159852808

我们可以看到关于原始Website对象及其克隆体的信息。查看id()函数的输出,可以看到这两个地址是不同的。

为什么要使用原型模式?

此外,我们还经常需要复制从数据库取出的对象,这些对象通常引用其他基于数据库的对象。克隆这样一个复杂的对象成本很高(需要对数据库进行多次查询),所以原型是解决这个问题的一种便捷方法。

原型模式的优点

  • 性能优良原型模式是在内存二进制流的拷贝,要比直接new一个对象性能好很多,特别是要在一个循环体内产生大量的对象时,原型模式可以更好地体现其优点。
  • 逃避构造函数的约束这既是它的优点也是缺点,直接在内存中拷贝,构造函数是不会执行的。优点就是减少了约束,缺点也是减少了约束,需要大家在实际应用时考虑。

原型模式的使用场景

  • 资源优化场景类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等。

  • 性能和安全要求的场景通过new产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。

  • 一个对象多个修改者的场景一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用。在实际项目中,原型模式很少单独出现,一般是和工厂方法模式一起出现,通过clone的方法创建一个对象,然后由工厂方法提供给调用者。

参考书籍

《设计模式之禅(第2版)》《精通Python设计模式(第2版)》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值