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.allowReplace = allowReplace
def setBean(self,beanName,resource,*args,**kwargs):
if not self.allowReplace:
assert not beanName t,"该BeanFactory不允许重复注⼊%r,请修改beanName" % beanName
def call():
"""定义⼀个函数闭包,如果注⼊的resource是可调⽤类型,就将*args和**kwargs传⼊并调⽤该函数,然后将返回值返回如果是⼀个不可调⽤对象,就直接返回
"""
if callable(resource):
return resource(*args,**kwargs)
else:
return resource
#将call闭包与beanName建⽴映射
def __getitem__(self,beanName):
"""重载__getitem__⽅法,使得BeanFactory⽀持使⽤[]获取beanName对应的注册的资源
"""
try:
# 从context字典中取出beanName对应的资源
writeline使用方法pythonresource = t[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__⽅法
sult # <-- .操作符会⾃动调⽤__getattr__
def __getattr__(self, name):
assert name == 'result', "Unexpected attribute request other then 'result'"
sult
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):
# title 由 RequiredResource('AppTitle',IsInstanceOf(str))⽣成
#'AppTitle'对应的值在__main__代码块注册了⼀个值
for f in self.flist:
class BetterConsole(Component):
def __init__(self, prefix=''):
self.prefix = prefix
def WriteLine(self, s):
lines = s.split('\n')
for line in lines:
if line:
print(self.prefix, line)
else:
print
def GetCurrentUser():
v('USERNAME') or 'Some User' # USERNAME is platform-specific
def ShowDir():
return os.listdir()
if __name__ == '__main__':
print('\n*** 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()
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论