Kra*_* Li 3 python plugins factory composition openstack-neutron
我在openstack中子读了下面的代码.
class APIRouter(wsgi.Router):
@classmethod
def factory(cls, global_config, **local_config):
return cls(**local_config)
def __init__(self, **local_config):
# do something. Not using local_config
Run Code Online (Sandbox Code Playgroud)
我这里有两个问题.
从工厂代码我们可以知道它用于创建APIRouter
实例.但为什么我们需要呢?为什么我们不只是api_router = ApiRouter()
用来获取实例?
在__init__
和工厂,local_config
并global_config
没有使用.为什么我们在功能中定义它?
我想使用工厂而不是构造函数应该有一些优势.就像JAVA中的设计模式一样.我希望答案可以说明优势或原因.更好的一些exapmle
这是一个尖锐的问题.我打算(希望,知情)猜测.我猜是因为虽然我已经回顾了有问题的OpenStack代码,但它不是我的代码,也不是我使用这种特定的配置架构.
APIRouter()
在源代码中出现作为主实例构造函数.APIRouter.factory
主要与粘贴部署设计相关,用于使用静态配置文件指定中间件服务/处理管道.
业界有着丰富的历史,他们认为可组合模块的处理框架 - 插件体系结构庞大 - 将是一种可靠,高效的方式来构建具有很高市场成功可能性的网络服务.这个梦想至少在20世纪80年代早期回归到UNIX System V的STREAMS.插件架构经常工作 - 有时很巧妙.然而,很少有这样的框架能够取得成功,而是独立于其他原因已经非常成功的产品或供应商.那么WordPress,nginx,Apache或PostgreSQL的插件系统呢?首都!一个插件系统应该协调所有四个,以及其他几十个不同的引擎?可能是"过得太远的桥梁".但我的愤世嫉俗离题了.
工厂函数(或此处,工厂方法)在任何人可能想要决定使用什么类型的对象而不依赖于继承层次结构时都有意义.例如,想象一下API路由器的两种实现:FastAPIRouter
非常快,但只支持REST.StandardAPIRouter
速度较慢,但它支持REST或SOAP请求.如果你打电话给FastAPIRouter()
aka FastAPIRouter.__init__()
,你只能得到一个FastAPIRouter
实例.但是如果FastAPIRouter.factory(...)
使用指示需要SOAP功能的参数调用,则该工厂方法可以选择回送StandardAPIRouter
实例.你可能没有得到你所要求的精确的东西,但你得到的东西可以满足你的需要.这通常更有价值.工厂是构造函数,但可以选择子类来构造.标准构造函数无法选择.
如果你不喜欢构建彼此实例的兄弟类中固有的紧密耦合,你可以想象一个普遍的请求APIRouter.factory(...)
会产生一个"命令决定",它根据它(可能是更好的)对最好的理解来回传实现来处理给定的参数.仍然存在耦合......但它提供了智慧和价值.
这就像在一家餐馆,并向错误的服务器询问一些事情.一个可能的回答是"不!这不是我的桌子." 没有客户赞赏这一点.更好的回答是"杰克是你的服务器.我会帮你的." 这就是工厂方法可以做的.它们不是课堂特殊方法的一部分; 缺乏特定的,刚性的构造函数,它们可以更加宽松,甚至可以用更合适的对象代替最初请求的对象.
你偶尔会在Python中看到工厂.collections.namedtuple
是一个伟大的,有点神奇的例子.它不只是从预先存在的固定列表中选择一个类; 它实际上根据您的规格从整个布料中创建了一个新类.但是,Python,Ruby,Perl和JavaScript等动态语言不像Java这样的静态类型语言需要工厂.他们的构造函数具有与Java相同的约束,但语言也具有动态类型("后期绑定"),鸭子类型,以及开发人员使用委托和继承的意愿.这一系列特征为选择"正确的工作对象"提供了更大的自由度.无论是技术需求还是文化选择,Java开发人员都更加依赖
工厂模式来提高灵活性.
还要考虑历史:今天的许多中间件开发人员在其庞大的生态系统中花费了大量时间在Java上进行技术和经济工作.毫无疑问,Java的"软件工程"领域的模式和实践,如测试,依赖注入和子系统组合已经扩展到其他语言社区.一旦模式,期望和术语得到很好的建立,它们就会持续存在.
因此,在技术上和其他方面,.factory()
在Neutron中使用构造函数是有意义的.
但实际上有几个"但......".
我不能声称已经看到了世界上所有的Neutron代码,但我见过的代码实际上并没有使用工厂.APIRouter.factory
比起APIRouter.__init__
稍微改变的呼叫顺序更有吸引力.与开发人员的敏感性和标准化的架构呼叫签名保持一致 - 这些签名本身就很有价值.但这是一个狭隘的技术性,因为Neutron同样可以指定标准构造函数的调用签名.目前的工厂实际上并没有使用他们的参数或添加智能.它们是备考工厂,也是事实上的替代建造者.
整个paste-deploy
方法是在配置文件中指定所需的组件.这导致人们明确选择所需的类,限制灵活的"我们应该构建什么样的对象?"的需要和价值.代码中的选择.就像动态语言的自由度使工厂大放异彩一样,配置文件会降低工厂在中间件组合中的价值.
至于你的第二个问题,为什么配置设置未使用?大概是因为APIRouter
不需要它们.其他一些模块(例如处理版本控制和IPAM可插入过滤器)确实似乎使用本地或全局配置对象(尽管只是传递).我非常喜欢使用未使用的配置选项,就像工厂方法一样:它们是组合系统的架构特性,实际上并没有大量使用,而且恰好是不必要的APIRouter
.
摘要
工厂允许更灵活的对象创建.一种语言越严格和以继承为重点,工厂模式就越必要.作为插件框架或可扩展服务器的一个特性,它们非常合理.但在这种特殊情况下,工厂的使用非常轻微.
即使工厂在当前代码中使用不多,您也可以认为它们是有意义的,因为外部模块或未来版本可以更广泛地使用.并非所有架构元素最初都需要用作框架的一部分.