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/视图中定义。