是否有描述以下设置的设计模式?这个设计是否有任何重大问题?
类Widget
实例可以由“哑”构造函数Widget.__init__()
构建,也可以由“智能”工厂方法Workbench.upgrade_widget()
构建:
class Widget:
def __init__(self, abc, def, ...):
self.abc = abc
self.def = def
...
...
class Workbench:
# widget factory function, which uses data from the workbench instance
def upgrade_widget(self, widget, upgrade_info):
widget = Widget(widget.abc, widget.def, ...)
# I will modify the widget's attributes
...
self.rearrange_widget(widget, xyz) # modifies widget's internal state
...
widget.abc = ... # also modifies widget's state
...
return widget
# uses data from the workbench instance
def rearrange_widget(self, widget, xyz):
...
# this class does other stuff too
...
小部件是不可变的,因为在完全初始化之后我不能修改它的实例(很多代码依赖于这个不变量)。但我发现在初始化时修改小部件非常方便,并使代码更清晰。
我主要担心的是我在另一个类中修改了“不可变”小部件。如果它只在upgrade_widget
中,我可能会使用它,因为它不会修改传递给它的小部件。但是该方法依赖于其他Workbench
方法(rearrange_widget
),这些方法修改了它作为参数接收的窗口小部件。我觉得我无法控制这个“不可变”实例的实际修改位置 - 有人可能会意外地使用已经完全初始化的小部件调用rearrange_widget
,从而导致灾难。
答案 0 :(得分:1)
你现在如何强制执行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()。例如,rearrange_widget应该在执行任何操作之前检查窗口小部件是否已解锁。
尽管存在恶意篡改实例,但无论如何都会发生这种情况。它也不会阻止属性被自己的方法改变。
请注意,我上面写的代码(伪python)没有经过测试,但希望它能说明如何处理主要问题的一般概念。
哦,我不确定这种模式是否有特定名称。
答案 1 :(得分:1)
@chees:这样做的一种更简洁的方法是修改__dict__
中的__init__
,并使__setattr__
始终引发异常(顺便说一下,{{1}不是一个好主意} - 它只是为了一般):
raise Exception
在Workbench中以相同的方式修改它(即使用class Widget:
def __init__(self, args):
self.__dict__['args'] = args
def __setattr__(self, name, value):
raise TypeError
)不断提醒你,你正在做一些你不应该做的事情。