【发布时间】:2010-11-09 14:13:05
【问题描述】:
更新问题,见下文
我正在开始一个新项目,我想试验基于组件的架构(我选择了PyProtocols)。这是一个显示实时图形并与之交互的小程序。
我从设计用户输入组件开始:
-
IInputDevice - 例如鼠标、键盘等... InputDevice 可能有一个或多个输出通道:
- IOutput - 包含单个值(例如 MIDI 滑块的值)的输出通道
- ISequenceOutput - 包含一系列值的输出通道(例如,代表鼠标位置的 2 个整数)
- IDictOutput - 一个包含命名值的输出通道(例如,键盘每个键的状态,由键盘符号索引)
现在我想定义接口来过滤这些输出(平滑、抖动、反转等...)。
我的第一种方法是创建一个 InputFilter 接口,它对连接到的每种输出通道都有不同的过滤器方法...但是 PyProtocols 文档中的介绍清楚地表明整个接口和适配器是关于避免类型检查!
所以我的猜测是我的 InputFilter 接口应该是这样的:
- IInputFilter - 过滤 IOutput
- ISequenceInputFilter - 过滤 ISequenceOutput
- IDictInputFilter - 过滤 IDictOutput
然后我可以在 I*Ouptut 接口中有一个 connect() 方法,它可以神奇地调整我的过滤器并使用适合输出类型的过滤器。
我试图实现它,它有点工作:
class InputFilter(object):
"""
Basic InputFilter implementation.
"""
advise(
instancesProvide=[IInputFilter],
)
def __init__(self):
self.parameters = {}
def connect(self, src):
self.src = src
def read(self):
return self.src.read()
class InvertInputFilter(InputFilter):
"""
A filter inverting single values.
"""
def read(self):
return -self.src.read()
class InvertSequenceInputFilter(InputFilter):
"""
A filter inverting sequences of values.
"""
advise(
instancesProvide=[ISequenceInputFilter],
asAdapterForProtocols=[IInputFilter],
)
def __init__(self, ob):
self.ob = ob
def read(self):
res = []
for value in self.src.read():
res.append(-value)
return res
现在我可以根据输出类型调整过滤器:
filter = InvertInputFilter()
single_filter = IInputFilter(filter) # noop
sequence_filter = ISequenceInputFilter(filter) # creates an InvertSequenceInputFilter instance
single_filter 和 sequence_filter 具有正确的行为并产生单一和序列数据类型。现在如果我在同一个模型上定义一个新的 InputFilter 类型,我会得到这样的错误:
TypeError: ('Ambiguous adapter choice', <class 'InvertSequenceInputFilter'>, <class 'SomeOtherSequenceInputFilter'>, 1, 1)
我一定做错了什么,我的设计是否正确?或者我是否错过了如何实现我的 InputFilterS 的要点?
更新 2
我知道我在这里期待太多的魔法,适配器不会检查它们正在适应的对象,而只是查看它们提供的接口,这对我来说现在听起来很正常(记住我对这些概念很陌生!)。
所以我想出了一个新设计(精简到最低限度并省略了 dict 接口):
class IInputFilter(Interface):
def read():
pass
def connect(src):
pass
class ISingleInputFilter(Interface):
def read_single():
pass
class ISequenceInputFilter(Interface):
def read_sequence():
pass
所以 IInputFilter 现在是一种通用组件,实际使用的组件,ISingleInputFilter 和 ISequenceInputFilter 提供了专门的实现。现在我可以编写从专用接口到通用接口的适配器:
class SingleInputFilterAsInputFilter(object):
advise(
instancesProvide=[IInputFilter],
asAdapterForProtocols=[ISingleInputFilter],
)
def __init__(self, ob):
self.read = ob.read_single
class SequenceInputFilterAsInputFilter(object):
advise(
instancesProvide=[IInputFilter],
asAdapterForProtocols=[ISequenceInputFilter],
)
def __init__(self, ob):
self.read = ob.read_sequence
现在我这样写我的 InvertInputFilter:
class InvertInputFilter(object):
advise(
instancesProvide=[
ISingleInputFilter,
ISequenceInputFilter
]
)
def read_single(self):
# Return single value inverted
def read_sequence(self):
# Return sequence of inverted values
并将它与我会做的各种输出类型一起使用:
filter = InvertInputFilter()
single_filter = SingleInputFilterAsInputFilter(filter)
sequence_filter = SequenceInputFilterAsInputFilter(filter)
但是,同样的错误,这又一次惨败,这一次它是由 InvertInputFilter 定义直接触发的:
TypeError: ('Ambiguous adapter choice', <class 'SingleInputFilterAsInputFilter'>, <class 'SequenceInputFilterAsInputFilter'>, 2, 2)
(只要我在类的instancesProvide 子句中放置一个接口,错误就会消失)
更新 3
在对 PEAK 邮件列表进行了一些讨论之后,似乎最后一个错误是由于 PyProtocols 中的设计缺陷造成的,它在声明时会进行一些额外的检查。我用 zope.interface 重写了所有内容,并且效果很好。
【问题讨论】:
标签: python interface protocols