如何实现具有非局部相等性的装饰器?
大家好,目前我正在重构我的一个程序,发现了一个有趣的问题。
我在一个自动机里有状态转换。每个转换都有一个起始状态和一个结束状态。有些转换有标签,这个标签代表在进行转换时需要执行的某个动作。如果没有标签,就意味着不需要执行任何动作。有些转换还有条件,必须满足这个条件才能进行转换。如果没有条件,这个转换就像是在非确定性有限自动机(NFA)中的一个ε转换,可以在不消耗输入符号的情况下进行。
我需要以下操作:
- 检查这个转换是否有标签
- 获取这个标签
- 给一个转换添加标签
- 检查这个转换是否有条件
- 获取这个条件
- 检查两个转换是否相等
从前五点来看,这听起来像是一个清晰的装饰器模式,基本的转换和两个装饰器:带标签的和带条件的。然而,这种方法有个问题:如果两个转换的起始状态和结束状态相同,且两个转换的标签相同(或者都没有标签),条件也相同(或者都没有条件),那么这两个转换就被认为是相等的。使用装饰器的话,我可能会有两个转换 Labeled("foo", Conditional("bar", Transition("baz", "qux"))) 和 Conditional("bar", Labeled("foo", Transition("baz", "qux"))) ,这就需要一种非局部的相等比较,也就是说,装饰器需要收集所有的数据,而转换必须在一个集合基础上比较这些收集到的数据:
class Transition(object):
def __init__(self, start, end):
self.start = start
self.end = end
def get_label(self):
return None
def has_label(self):
return False
def collect_decorations(self, decorations):
return decorations
def internal_equality(self, my_decorations, other):
try:
return (self.start == other.start
and self.end == other.end
and my_decorations = other.collect_decorations())
def __eq__(self, other):
return self.internal_equality(self.collect_decorations({}), other)
class Labeled(object):
def __init__(self, label, base):
self.base = base
self.label = label
def has_label(self):
return True
def get_label(self):
return self.label
def collect_decorations(self, decorations):
assert 'label' not in decorations
decorations['label'] = self.label
return self.base.collect_decorations(decorations)
def __getattr__(self, attribute):
return self.base.__getattr(attribute)
这种方法算是干净的吗?我是不是漏掉了什么?
我现在有点困惑,因为我可以用更长的类名,通过合作多重继承来解决这个问题:
class Transition(object):
def __init__(self, **kwargs):
# init is pythons MI-madness ;-)
super(Transition, self).__init__(**kwargs)
self.start = kwargs['start']
self.end = kwargs['end']
def get_label(self):
return None
def get_condition(self):
return None
def __eq__(self, other):
try:
return self.start == other.start and self.end == other.end
except AttributeError:
return False
class LabeledTransition(Transition):
def __init__(self, **kwargs):
super(LabeledTransition).__init__(**kwargs)
self.label = kwargs['label']
def get_label(self):
return self.label
def __eq__(self):
super_result = super(LabeledTransition, self).__eq__(other)
try:
return super_result and self.label == other.label
except AttributeError:
return False
class ConditionalTransition(Transition):
def __init__(self, **kwargs):
super(ConditionalTransition, self).__init__(**kwargs)
self.condition = kwargs['condition']
def get_condition(self):
return self.condition
def __eq__(self, other):
super_result = super(ConditionalTransition, self).__eq__(other)
try:
return super_result and self.condition = other.condition
except AttributeError:
return False
# ConditionalTransition about the same, with get_condition
class LabeledConditionalTransition(LabeledTransition, ConditionalTransition):
pass
类 LabeledConditionalTransition 的行为完全符合预期,而且里面没有代码这点很吸引我,我觉得在这种情况下多重继承并不复杂。
当然,第三种选择就是把所有东西都塞进一个单一的转换类里,里面有一堆 has_label/has_transition 的方法。
所以……我现在很困惑。我是不是漏掉了什么?哪种实现看起来更好?你们是怎么处理类似的情况的?也就是说,某些对象看起来像是装饰器可以处理的,但随后又出现了这种非局部的方法?
编辑: 添加了 ConditionalTransition 类。基本上,这个类的行为就像装饰器,只是没有装饰器创建顺序带来的影响,转换会检查起始和结束状态是否正确,LabeledTransition 类会检查标签是否正确,而 ConditionalTransition 会检查条件是否正确。
2 个回答
从发布的代码来看,Transition和Labeled Transition之间唯一的区别就是它们在get_label()和has_label()这两个函数的返回值上。因此,你可以把这两者合并成一个类,只需要设置一个标签属性为None就可以了。
return self.label is not None
在has_label()函数中也是如此。
你能把ConditionalTransition
类的代码发出来吗?我觉得这样会更清楚。
我觉得很明显,大家都不太明白你的问题。建议你把问题放在一个具体的背景中,并且简化一下。比如,这里有一个用Python实现状态模式的例子,你可以看看,了解一下这个概念。
class State(object):
def __init__(self, name):
self.name = name
def __repr__(self):
return self.name
class Automaton(object):
def __init__(self, instance, start):
self._state = start
self.transitions = instance.transitions()
def get_state(self):
return self._state
def set_state(self, target):
transition = self.transitions.get((self.state, target))
if transition:
action, condition = transition
if condition:
if condition():
if action:
action()
self._state = target
else:
self._state = target
else:
self._state = target
state = property(get_state, set_state)
class Door(object):
open = State('open')
closed = State('closed')
def __init__(self, blocked=False):
self.blocked = blocked
def close(self):
print 'closing door'
def do_open(self):
print 'opening door'
def not_blocked(self):
return not self.blocked
def transitions(self):
return {
(self.open, self.closed):(self.close, self.not_blocked),
(self.closed, self.open):(self.do_open, self.not_blocked),
}
if __name__ == '__main__':
door = Door()
automaton = Automaton(door, door.open)
print 'door is', automaton.state
automaton.state = door.closed
print 'door is', automaton.state
automaton.state = door.open
print 'door is', automaton.state
door.blocked = True
automaton.state = door.closed
print 'door is', automaton.state
这个程序的输出结果是:
door is open
closing door
door is closed
opening door
door is open
door is open