2009-07-10 56 views
3

更新的问题,请参见下面菜鸟组件设计问题

我开始一个新项目,我想与部件试验基础架构(我选择了PyProtocols)。这是一个显示和实时图形交互的小程序。

我开始通过设计用户输入组件:

  • IInputDevice - 例如鼠标,键盘,等等的可的InputDevice具有一个或多个输出信道:
    • IOutput - 包含单个值(例如,MIDI滑块的值)
    • ISequenceOutput的输出通道 - 包含的值(例如2个整数表示鼠标位置)的序列
    • IDictOutput输出信道 - 包含名为值的输出信道(例如在键盘的每个键,通过键盘符号索引的状态)

现在我想定义接口来过滤那些输出(平滑,抖动,反转等)。

我的第一种方法是创建一个InputFilter接口,它为每种输出通道连接了不同的过滤方法......但PyProtocols文档中的介绍清楚地表明,整个接口和适配器的事情是关于避免类型检查!

所以我的猜测是,我的输入过滤器的接口应该是这样的:

  • 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有正确的行为和产生单个和序列数据类型。现在,如果我在同一个模型中定义一个新的输入过滤器的类型,我得到的错误是这样的:

TypeError: ('Ambiguous adapter choice', <class 'InvertSequenceInputFilter'>, <class 'SomeOtherSequenceInputFilter'>, 1, 1) 

我必须做一些可怕的错误,是我设计的,即使正确吗?或者,我是否错过了如何实现我的InputFilterS?

更新2

我明白我期待有点太多魔力这里,适配器没有类型检查正在修改的对象,只是看他们提供的接口,它现在听起来正常的我(记住我是这些概念的新手!)。

于是我想出了一个新的设计(剥离到最低限度,并且省略了快译通接口):

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) 

更新3

的PEAK邮件列表上的一些讨论后(只要我把只有一个接口在类的instancesProvide条款的错误在前看不见),似乎这最后一个错误是由于PyProtocols中的设计缺陷造成的,它在声明时会做一些额外的检查。我用zope.interface重写了所有内容,并且完美地工作。

回答

1

我还没有使用PyProtocols,只有Zope组件架构,但它们足够相似,这些原则是相同的。

你的错误是你有两个适配器可以适应相同的事情。你们都有一个平均滤波器和一个反转滤波器。然后当你问过滤器时,两者都被找到,并且你得到了“ambigous adapter”错误。

你可以通过具有不同的接口来处理平均滤波器和反相滤波器,但它变得愚蠢。在Zope组件体系结构中,您通常会使用命名适配器来处理这种情况。每个适配器都会获取一个名称,默认为“'。在这种情况下,您可以给出适配器名称,如“求平均值”和“反相”,然后您可以使用该名称查找它们,以便知道是否获得平均值或反相滤波器。

对于更一般的问题,如果设计是否有意义,很难说清楚。你有三种不同的输出和三种不同的滤波器似乎不是一个好主意。也许你可以将序列和字典输出组合成单个值输出的组合,这样每个输出值都可以得到它自己的对象,所以它可以被独立地过滤。这对我来说会更有意义。

+0

谢谢,现在我更好地了解适配器如何工作。 指定的适配器在PyProtocols中不可用,如果我理解的很好,它们只是语法糖,并且它基本上与我的每个过滤器具有不同接口的情况基本相同(我希望能够在单独的插件中创建过滤器,无需创建新的界面或独特的名称)。 我不想做作文,因为它会产生类型检查,这正是我想要首先避免的。 – 2009-07-10 15:41:55