简介
上一篇文章我们讲解了单例模式,扩展了全局变量。这次我们来聊聊创建型中的最后一种模式——原型模式。
正文
原型,顾名思义是有一个原本,其他的都是这个原本的复制体。如果说单例模式是独生子女的话。那么原型模式则是克隆人。
下面我们简单实现一下:
import copy
class A:
def __new__(cls):
print("开始创建了")
return super().__new__(cls)
def __init__(self):
self.name = "原型"
def copy(self):
return copy.deepcopy(self)
a = A()
print(a,id(a),a.name)
b = b = a.copy()
print(b,id(b),b.name)
在其他的文章中,有看过这么一段话:通过复制一个已经存在的实例来获得一个新的实例,以避免重复创建此类实例带来的开销。
我们来实验一下:
import copy
import time
class A:
def __new__(cls):
time.sleep(10)
print("开始创建了")
return super().__new__(cls)
def __init__(self):
self.name = "原型"
def copy(self):
return copy.deepcopy(self)
a = A()
print(a,id(a),a.name)
b = a.copy()
print(b,id(b),b.name)
实验结果可以看出,很明显深拷贝是重新创建了一个实例,并且同样要花费相同的时间。所以说并没有节省重新创建的开销。那么那段话是什么意思呢?
我们再看看下面这个例子
import copy
import time
class A:
def __new__(cls):
time.sleep(10)
print("开始创建了")
return super().__new__(cls)
def __init__(self):
self.name = "原型"
def copy(self):
return copy.deepcopy(self)
a = A()
print(a,id(a),a.name)
b = a
b.__setattr__("age",18)
print(b,id(b),b.name)
print(a,id(a),a.name,a.age)
在这个例子中,我们可以看出只创建了一个实例,同时b修改后,a也会跟着修改,但是并没有多创建一个实例,而是为原有的实例增加了一个强引用。这就是浅拷贝。
虽然说这种方法确实是节省了创建实例的消耗,但是不符合原型模式的定义。就像今天克隆人意外残疾了,原本也需要残疾,还连带着其他克隆人一起残疾。
那么真正诠释那段话的是什么情况呢?我们再来看看下面这个例子
import copy
class A:
def __new__(cls):
print("开始创建了")
return super().__new__(cls)
def __init__(self):
self.name = "原型"
def copy(self):
return copy.deepcopy(self)
a = A()
a.__setattr__("age",13)
b = a.copy()
print(b,id(b),b.name,b.age)
这个例子中我们同样使用了深拷贝,但是在使用深拷贝前,对a做了一些处理。然后我们可以发现,克隆后的b也有a处理过的属性。
假如今天对a需要添加100个属性,用了原型模式就只需要copy就可以生成b了,而不需要为b也进行100次的添加操作。
总结
对于创建后的实例,需要有多个版本的时候,又不想重复之前的设置动作,就可以使用原型模式,在已有的版本上创建一个新的版本。像数据库和git的多版本管控就可以用到这种方式。