• Python实现IOC控制反转


    思路:

    用一个字典存储beanName和资源
    初始化时先将beanName和资源注册到字典中
    然后用一个Dscriptor类根据beanName动态请求资源,从而实现控制反转

    # -*- coding:utf-8 -*-
    import os
    class BeanFactory: 
        """
        Python版控制反转
        context: 存储bean的名字和对应的类或者值的字典
        allowRepalce: 是否允许替换已经注入的bean
        """
    
        def __init__(self,allowReplace=False):
            """构造函数
            allowReplace:是否允许替换已经注入的bean
            """
            self.context = {}
            self.allowReplace = allowReplace
        def setBean(self,beanName,resource,*args,**kwargs):
            if not self.allowReplace:
                assert not beanName in self.context,"该BeanFactory不允许重复注入%r,请修改beanName" % beanName
            def call():
                """定义一个函数闭包,如果注入的resource是可调用类型,就将*args和**kwargs传入并调用该函数,然后将返回值返回
                如果是一个不可调用对象,就直接返回
                """
                if callable(resource):
                    return resource(*args,**kwargs)
                else:
                    return resource
            #将call闭包与beanName建立映射
            self.context[beanName]=call
        def __getitem__(self,beanName):
            """重载__getitem__方法,使得BeanFactory支持使用[]获取beanName对应的注册的资源
            """
            try:
                # 从context字典中取出beanName对应的资源
                resource = self.context[beanName]
            except KeyError:
                raise KeyError("%r 未注册" % beanName)
            # 返回闭包函数调用后的结果
            return resource()
    
    AppFactory = BeanFactory()
    
    def NoAssertion(obj): return True
    
    def IsInstanceOf(*classes):
       def test(obj): return isinstance(obj, classes)
       return test
    
    def HasAttributes(*attributes):
       def test(obj):
          for each in attributes:
             if not hasattr(obj, each): return False
          return True
       return test
    
    def HasMethods(*methods):
       def test(obj):
          for each in methods:
             try:
                attr = getattr(obj, each)
             except AttributeError:
                return False
             if not callable(attr): return False
          return True
       return test
    
    
    #
    #
    #Descriptor就是一类实现了__get__(), __set__(), __delete__()方法的对象
    #若一个类的成员是descriptor,在访问它的值时是通过__get__()函数访问的
    #用这个特性实现在访问一个类的成员时自动到BeanFactory中请求对应的资源
    
    class RequiredResource(object):
       def __init__(self, beanName, assertion=NoAssertion):
          self.beanName =  beanName
          self.assertion = assertion
       def __get__(self, obj, T):#每次访问descriptor时都会调用__get__方法
          return self.result # <-- .操作符会自动调用__getattr__
       def __getattr__(self, name):
          assert name == 'result', "Unexpected attribute request other then 'result'"
          self.result = self.Request()
          return self.result
       def Request(self):
          obj = AppFactory[self.beanName]
          assert self.assertion(obj), 
                 "The value %r of %r does not match the specified criteria" 
                 % (obj, self.feature)
          return obj
    
    
    
    
    class Component(object):
       "Symbolic base class for components"
    class Bar(Component):
       # HasMethods是一个闭包函数,传入RequiredResource后用于检查'Console'
       # 对应的注册的那个feature是否有'WriteLine'方法
       # IsinstanceOf(str) 是一个闭包,传入RequiredResource后会被调用,用于
       # 检查注册的'AppTitle'对应资源是否是一个字符串
       # IsinstanceOf(str) 是一个闭包,传入RequiredResource后会被调用,用于
       # 检查'CurrentUser'对应的资源是否是一个字符串
    
       # RequiredFeatuire是desciptor,每次访问descriptor(即实现了__get__的类),都会先经过__get__函数。
    
       con   = RequiredResource('Console', HasMethods('WriteLine'))
       title = RequiredResource('AppTitle', IsInstanceOf(str))
       user  = RequiredResource('CurrentUser', IsInstanceOf(str))
       flist = RequiredResource('show_dir',IsInstanceOf(list))
       def __init__(self):
          self.X = 0
       def PrintYourself(self):
          self.con.WriteLine('-- Bar instance --')
          # title 由 RequiredResource('AppTitle',IsInstanceOf(str))生成
          #'AppTitle'对应的值在__main__代码块注册了一个值
          self.con.WriteLine('Title: %s' % self.title)
          self.con.WriteLine('User: %s' % self.user)
          self.con.WriteLine('X: %d' % self.X)
          for f in self.flist:
               self.con.WriteLine(f)
    
    class BetterConsole(Component):
       def __init__(self, prefix=''):
          self.prefix = prefix
       def WriteLine(self, s):
          lines = s.split('
    ')
          for line in lines:
             if line:
                print(self.prefix, line)
             else:
                print
    
    
    def GetCurrentUser():
       return os.getenv('USERNAME') or 'Some User' # USERNAME is platform-specific
    def ShowDir():
        return os.listdir()
    
    if __name__ == '__main__':
       print('
    *** IoC Demo ***')
       #Provide(feature,provider,*args,**kwargs) feature是要生成的对象的父类类型 provider是要注入的子类或者值
       AppFactory.setBean('AppTitle', 'Inversion of Control ...
    
    ... The Python Way')
       AppFactory.setBean('CurrentUser', GetCurrentUser)
       AppFactory.setBean('Console', BetterConsole, prefix='-->') # <-- transient lifestyle
       AppFactory.setBean('show_dir',ShowDir)
    
       bar = Bar()
       bar.PrintYourself()
    
  • 相关阅读:
    让本地仓库和远程仓库关联
    指定本地仓库与github上的test项目相连
    Git 指令
    DOS命令+++GITHUP用法
    xml
    渲染数据的方法
    php
    css3的过渡、动画、2D、3D效果
    渲染数据
    ajax
  • 原文地址:https://www.cnblogs.com/infoflow/p/8975264.html
Copyright © 2020-2023  润新知