代码之家  ›  专栏  ›  技术社区  ›  Luper Rouch François Lagunas

noob组件设计问题

  •  3
  • Luper Rouch François Lagunas  · 技术社区  · 15 年前

    更新的问题,见下文

    我正在启动一个新项目,我想尝试基于组件的体系结构(我选择了 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):
            # 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重写了所有内容,它工作得很好。

    1 回复  |  直到 15 年前
        1
  •  1
  •   Lennart Regebro    15 年前

    我没有使用PyProtocol,只使用Zope组件体系结构,但是它们非常相似,足以使这些原则保持一致。

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

    你可以通过使用不同的接口来处理这个问题,比如平均过滤器和反转过滤器,但是这会变得很愚蠢。在Zope组件体系结构中,通常使用命名适配器处理这种情况。默认情况下,每个适配器都会得到一个名称。在这种情况下,您会给适配器命名,如“平均值”和“反转”,然后使用该名称查找它们,这样您就知道是获得平均值还是反转过滤器。

    对于更一般的问题,如果设计合理与否,就很难说了。有三种不同类型的输出和三种不同类型的过滤器似乎不是一个好主意。也许您可以将序列和dict输出组合成单值输出,这样每个输出值都会得到它自己的对象,因此可以独立地对其进行过滤。这对我来说更有意义。