Python 修改工厂函数中的不可变对象
是否有描述以下设置的设计模式?该设计是否存在任何重大问题 类Python 修改工厂函数中的不可变对象,python,design-patterns,constructor,immutability,software-design,Python,Design Patterns,Constructor,Immutability,Software Design,是否有描述以下设置的设计模式?该设计是否存在任何重大问题 类Widget实例可以通过“哑”构造函数Widget.\uuu init\uuu(),或通过“智能”工厂方法工作台来构建。升级\u Widget(): 小部件是不可变的,因为我不能在它们完全初始化之后修改它们的实例(很多代码都依赖于这个不变量)。但是我发现在初始化小部件时修改它们非常方便,并且使代码更干净 我主要关心的是在不同的类中修改“不可变”的小部件。如果它只是在升级\u widget中,我可能会接受它,因为它不会修改传递给它的wid
Widget
实例可以通过“哑”构造函数Widget.\uuu init\uuu()
,或通过“智能”工厂方法工作台来构建。升级\u Widget()
:
小部件是不可变的,因为我不能在它们完全初始化之后修改它们的实例(很多代码都依赖于这个不变量)。但是我发现在初始化小部件时修改它们非常方便,并且使代码更干净
我主要关心的是在不同的类中修改“不可变”的小部件。如果它只是在
升级\u widget
中,我可能会接受它,因为它不会修改传递给它的widget。但是该方法依赖于其他Workbench
方法(reareat\u widget
),这些方法修改它作为参数接收的widget。我感觉我正在失去对这个“不可变”实例的实际修改位置的控制——有人可能会意外地调用重新排列\u widget
,而该widget已经完全初始化,这将导致一场灾难。您现在如何强制实现该widget的不可变性
如果将“锁定”属性添加到小部件中,并包装setattr以检查该属性,该怎么办
class Widget(object):
__locked = False
def __init__(self,a,b,c,locked=True):
...
self.__locked = locked
def lock(self):
self.__locked = True
def is_locked(self):
return self.__locked
def __setattr___(self,*args,**kw):
if self.__locked:
raise Exception('immutable') # define your own rather than use Exception
return super(Widget).__setattr__(self,*args,**kw)
然后在工厂里:
class Workbench(object):
def upgrade_widget(self,widget,upgrade_info):
widget = Widget(widget.a,widget.b,...,locked=False)
self.rearrange_widget(widget, blah)
widget.c = 1337
widget.lock()
return widget
在一般情况下,您可以非常肯定,一旦类被锁定,它就不会发生任何有趣的事情。任何关心小部件不变性的方法都应该检查该小部件的is_locked()。例如,在做任何事情之前,重排小部件应该检查小部件是否也已解锁
尽管存在恶意篡改实例的情况,但无论如何都可能发生这种情况。它也不能防止属性被自己的方法改变
请注意,我上面编写的代码(伪python)没有经过测试,但希望它说明了如何处理主要问题的一般思路
哦,我不确定这个模式是否有一个特别的名字。@chees:一个更简洁的方法是修改
\uuuuuu dict\uuuuuu
中的\uu init\uuuuuuuu
并使\uuuuu setattr\uuuuuuuuuuuuu
总是引发异常(顺便说一句,引发异常不是一个好主意,只是一般性的):
在Workbench中以同样的方式修改它(即使用\uuuu dict\uuuu
)会不断提醒您正在做一些不应该做的事情。除了这个问题:在Python2中,始终从“object”继承类-否则您可能会缺少特性,难以诊断错误行为,因为不从对象继承的类是老式类。对不起,应该说它是Python 3…顺便说一句,每当我这样做时,我通常在它自己的类中实现锁定并从它继承。。。类似于类可锁定(对象):。。。类小部件(可锁定):…同意不引发异常-为了方便起见,您需要实现自己的异常(我将对此发表评论)。我确实发现,如果你不得不大量使用dict访问属性,那么通过dict访问属性会有点拖拉,尽管这确实是一个很好的抑制因素……确切地说。有时,您希望API成为一个拖拽,以提醒您不应该真正这样做,就像从类外部访问一个双下划线的私有属性一样。
class Workbench(object):
def upgrade_widget(self,widget,upgrade_info):
widget = Widget(widget.a,widget.b,...,locked=False)
self.rearrange_widget(widget, blah)
widget.c = 1337
widget.lock()
return widget
class Widget:
def __init__(self, args):
self.__dict__['args'] = args
def __setattr__(self, name, value):
raise TypeError