更新的问题,见下文
我正在启动一个新项目,我想尝试基于组件的体系结构(我选择了
PyProtocols
)这是一个显示和实时图形交互的小程序。
我从设计用户输入组件开始:
-
输入设备
-例如鼠标、键盘等…输入设备可以有一个或多个输出通道:
-
输出量
-包含单个值的输出通道(例如MIDI滑块的值)
-
等产量
-包含一系列值的输出通道(例如2个表示鼠标位置的整数)
-
IDICT输出
-包含命名值的输出通道(例如,键盘的每个键的状态,由键盘符号索引)
现在我想定义接口来过滤这些输出(平滑、抖动、反转等等)。
我的第一个方法是创建一个inputfilter接口,它对连接到的每种输出通道都有不同的过滤方法…但是PyProtocols文档中的介绍清楚地表明,整个接口和适配器都是为了避免类型检查!
所以我猜我的inputfilter接口应该如下所示:
-
输入滤波器
-过滤器输出
-
ISequenceInputfilter(ISequenceInputfilter)
-筛选等序列输出
-
IDicInputfilter(IDicInputfilter)
-过滤器IDicOutput
然后我可以在i*ouput接口中有一个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具有正确的行为,并生成single和sequence数据类型。现在,如果我在同一个模型上定义一个新的inputfilter类型,我会得到如下错误:
TypeError: ('Ambiguous adapter choice', <class 'InvertSequenceInputFilter'>, <class 'SomeOtherSequenceInputFilter'>, 1, 1)
我一定是做错了什么,我的设计还对吗?或者我是否遗漏了如何实现输入过滤器的要点?
更新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):
def read_sequence(self):
要将其与各种输出类型一起使用,我将执行以下操作:
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重写了所有内容,它工作得很好。