注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

Code@Pig Home

喜欢背着一袋Code傻笑的Pig .. 忧美.欢笑.记忆.忘却 .之. 角落

 
 
 

日志

 
 

[trac] Component Architecture Implementation  

2010-03-24 17:06:49|  分类: scm_trac |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
书接上回,我们看到 trac 的 Component Architecture 挺有意思的,究其原理,还听我慢慢道来。
http://kasicass.blog.163.com/blog/static/395619201021661733897/

先看我下面 simple version 的实现。
Interface 就是个 marker。

ExtensionPoint, 通过继承 property 以及 extension() 借口,实现了 for ob in ... 的写法。
TodoList 中的 for ob in self.observers,调用了 ExtensionPoint.extensions,得到所有“实现了ITodoObserver“的 instance。

ComponentMeta
    _components, 记录了 component cls 唯一的 instance
                          { component_cls : component instance, ... }
    _registry, 记录了 interface_cls 对应的所有监听的 component_cls
                   { interface_cls : [component_cls1, component_cls2, ...], ... }

Component, __init__ 的时候 hack 了一下,保证只返回唯一的一个实例 ComponentMeta._components[cls]

implements = Component.implements
implements() 函数自动将 Component 注册到 ComponentMeta._registry 中的相关项。

------------ mvc.py -------------------------------
class Interface(object):
    """Marker base class for extension point interfaces."""

class ExtensionPoint(property):
    """Marker class for extension points in components."""

    def __init__(self, interface):
        property.__init__(self, self.extensions)
        self.interface = interface
        self.__doc__ = 'List of components that implement `%s`' % \
                       self.interface.__name__

    def extensions(self, component):
        extensions = ComponentMeta._registry.get(self.interface, ())
        return filter(None, [ComponentMeta._components[cls] for cls in extensions])

    def __repr__(self):
        return '<ExtensionPoint %s>' % self.interface.__name__

class ComponentMeta(type):
    _components = {}        # { component_cls : component instance, ... }
    _registry = {}          # { interface_cls : [component_cls1, component_cls2, ...], ... }

    def __new__(mcs, name, bases, d):
        """Create the component class."""

        new_class = type.__new__(mcs, name, bases, d)
        if name == 'Component':
            # Don't put the Component base class in the registry
            return new_class

        init = d.get('__init__')
        if not init:
            # Because we're replacing the initializer, we need to make sure
            # that any inherited initializers are also called.
            for init in [b.__init__._original for b in new_class.mro()
                if issubclass(b, Component) and '__init__' in b.__dict__]:
                    break

        components = ComponentMeta._components
        def maybe_init(self, init=init, cls=new_class):
            if cls not in components:
                components[cls] = self
                if init:
                    try:
                        init(self)
                    except:
                        del components[cls]
                        raise
        maybe_init._original = init
        new_class.__init__ = maybe_init

        registry = ComponentMeta._registry
        for cls in new_class.__mro__:
            for interface in cls.__dict__.get('_implements', ()):
                classes = registry.setdefault(interface, [])
                if new_class not in classes:
                    classes.append(new_class)

        return new_class

class Component(object):
    __metaclass__ = ComponentMeta

    def __new__(cls, *args, **kwargs):
        self = ComponentMeta._components.get(cls)
        if self is None:
            self = super(Component, cls).__new__(cls)
        return self

    @staticmethod
    def implements(*interfaces):
        import sys

        frame = sys._getframe(1)
        locals_ = frame.f_locals

        # Some sanity checks
        assert locals_ is not frame.f_globals and '__module__' in locals_, \
               'implements() can only be used in a class definition'

        locals_.setdefault('_implements', []).extend(interfaces)

implements = Component.implements
-------- foo.py -----------------------------------
from mvc import *

#
# Component: TodoList
#

class ITodoObserver(Interface):
    def todo_added(name, desc):
        pass

class TodoList(Component):
    observers = ExtensionPoint(ITodoObserver)

    def __init__(self):
        self.todos = {}

    def add(self, name, desc):
        assert not name in self.todos, 'To-do already in list'
        self.todos[name] = desc
        for ob in self.observers:
            ob.todo_added(name, desc)

#
# Component: TodoPrinter
#

class TodoPrinter(Component):
    implements(ITodoObserver)

    def todo_added(self, name, desc):
        print 'TODO:', name
        print '     ', desc

#
# test
#

if __name__ == '__main__':
    printer   = TodoPrinter()
    todo_list = TodoList()
    todo_list.add('kasicass', 'lalala')
    todo_list.add('ylhu', 'play like a water dragon')

    todo_list2 = TodoList()
    print todo_list == todo_list2
-------------------------------------------------
$ python foo.py
TODO: kasicass
      lalala
TODO: ylhu
      play like a water dragon
True
-------------------------------------------------

对于 trac,其增加了 ComponentManager,将上面 ComponentMeta._components 做的事情,独立管理起来了。
  评论这张
 
阅读(630)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017