4.6. 接口和适配器

接口与面向对象编程是一样的。 interfaces .适配器是指一个众所周知的 adapter 在面向对象的应用程序中帮助分离关注点的设计模式。

CubicWeb 适配器为实体类型提供逻辑功能。

适配器的定义非常简单。CubicWeb本身的摘录(在 cubicweb.entities.adapters ):

class ITreeAdapter(EntityAdapter):
    """This adapter has to be overriden to be configured using the
    tree_relation, child_role and parent_role class attributes to
    benefit from this default implementation
    """
    __regid__ = 'ITree'

    child_role = 'subject'
    parent_role = 'object'

    def children_rql(self):
        """returns RQL to get children """
        return self.entity.cw_related_rql(self.tree_relation, self.parent_role)

适配器对象具有 self.entity 表示正在调整的实体的属性。

注解

适配器带有由适配器的注册表标识符标识的服务概念,因此不再需要显式接口和 cubicweb.predicates.implements 选择器。你应该用 cubicweb.predicates.is_instance 当要在实体类型上选择时,或 cubicweb.predicates.adaptable 当您要在服务上选择时。

4.6.1. 专门化和绑定适配器

from cubicweb.entities.adapters import ITreeAdapter

class MyEntityITreeAdapter(ITreeAdapter):
    __select__ = is_instance('MyEntity')
    tree_relation = 'filed_under'

这里的itreeadapter提供了一个默认实现。这个实现实际上使用树关系类属性来帮助实现正确的行为。

在这里,我们提供一个特定的实现,它将被绑定到 MyEntity 实体类型 adaptee

4.6.2. 将代码从接口/混音器转换为适配器

这里我们举一个小例子。之前:

from cubicweb.predicates import implements
from cubicweb.interfaces import ITree
from cubicweb.mixins import ITreeMixIn

class MyEntity(ITreeMixIn, AnyEntity):
    __implements__ = AnyEntity.__implements__ + (ITree,)


class ITreeView(EntityView):
    __select__ = implements('ITree')
    def cell_call(self, row, col):
        entity = self.cw_rset.get_entity(row, col)
        children = entity.children()

后:

from cubicweb.predicates import adaptable, is_instance
from cubicweb.entities.adapters import ITreeAdapter

class MyEntityITreeAdapter(ITreeAdapter):
    __select__ = is_instance('MyEntity')

class ITreeView(EntityView):
    __select__ = adaptable('ITree')
    def cell_call(self, row, col):
        entity = self.cw_rset.get_entity(row, col)
        itree = entity.cw_adapt_to('ITree')
        children = itree.children()

正如我们所看到的,接口/混合对偶性消失了,实体类本身完全摆脱了这些关注。如果要使用实体的ITree接口,请调用其 cw_adapt_to 方法获取此接口的适配器,然后访问适配器上接口的成员

让我们来看一个例子,我们自己定义了一切。我们从以下开始:

class IFoo(Interface):
    def bar(self, *args):
        raise NotImplementedError

class MyEntity(AnyEntity):
    __regid__ = 'MyEntity'
    __implements__ = AnyEntity.__implements__ + (IFoo,)

    def bar(self, *args):
        return sum(captain.age for captain in self.captains)

class FooView(EntityView):
    __regid__ = 'mycube.fooview'
    __select__ = implements('IFoo')

    def cell_call(self, row, col):
        entity = self.cw_rset.get_entity(row, col)
        self.w('bar: %s' % entity.bar())

转换为:

class IFooAdapter(EntityAdapter):
    __regid__ = 'IFoo'
    __select__ = is_instance('MyEntity')

    def bar(self, *args):
        return sum(captain.age for captain in self.entity.captains)

class FooView(EntityView):
     __regid__ = 'mycube.fooview'
     __select__ = adaptable('IFoo')

     def cell_call(self, row, col):
         entity = self.cw_rset.get_entity(row, col)
         self.w('bar: %s' % entity.cw_adapt_to('IFoo').bar())

注解

将实体方法迁移到适配器时,代码可以按原样移动,但 self 在适配器中必须成为 self.entity .

4.6.3. 库中定义的适配器

更多在Web/视图中定义。