我读了下面的堆栈中子中的代码。

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


我在这里有两个问题。


从工厂代码中我们可以知道它用于创建APIRouter实例。但是为什么我们需要它?为什么我们不仅仅使用api_router = ApiRouter()获取实例?
__init__和工厂中,不使用local_configglobal_config。为什么我们在函数中定义它?


我想使用工厂而不是构造函数应该有一些优势。就像JAVA中的设计模式一样。我希望答案可以说明优点或原因。更好的例子

最佳答案

这是一个尖锐的问题。我将进行一个(希望是有见地的)猜测。我之所以这么说是因为,尽管我已经审查了有问题的OpenStack代码,但这不是我的代码,也不使用这种特定的配置体系结构。

APIRouter()在源代码中显示为主要实例构造函数。 APIRouter.factory主要出现在与paste-deploy设计的连接中,该设计用于使用静态配置文件指定中间件服务/处理管道。

该行业拥有丰富的历史,他们认为可组合模块的处理框架(即插件架构庞大)将是一种可靠且高效的方式来构建具有很大市场成功可能性的网络服务。这个梦想至少可以追溯到1980年代初的UNIX System V的STREAMS。插件体系结构经常起作用-有时是熟练的。然而,很少有这样的框架获得成功,但是它们独立于由于其他原因已经非常成功的产品或供应商。那么适用于WordPress,nginx,Apache或PostgreSQL的插件系统吗?首都!一个可以协调所有四个引擎以及数十种其他多样化引擎的插件系统吗?可能是“一座桥太远了”。但是我的犬儒主义离题。

无论何时何地想要独立于继承层次结构决定使用哪种类型的对象,工厂函数(或这里的工厂方法)都是有意义的。例如,想象一下API路由器的两种实现:FastAPIRouter确实非常快,但是仅支持REST。 StandardAPIRouter较慢,但它支持REST或SOAP请求。如果调用FastAPIRouter() aka FastAPIRouter.__init__(),则只能取回FastAPIRouter实例。但是,如果使用指示需要SOAP功能的参数调用FastAPIRouter.factory(...),则该工厂方法可以选择递回StandardAPIRouter实例。也许您没有得到您所要求的精确信息,但是您却得到了满足您需求的东西。这通常更有价值。工厂是构造函数,但工厂可以选择要构造的子类。标准构造函数无法选择。

如果您不喜欢构造彼此实例的同级类中固有的紧迫的coupling,则可以想象对APIRouter.factory(...)的一般请求会做出“命令决定”,该子类根据其(可能更好)递归)了解处理给定参数的最佳实现。耦合仍然存在...但是它提供了智能和价值。

这就像在餐厅里,向错误的服务器索要东西。一个可能的回答是“不!这不是我的桌子。”没有客户会欣赏。更好的回答是“杰克是您的服务器。我会为您找他。”那就是工厂方法可以做到的。它们不是类的特殊方法的一部分。缺少特定的,僵化的构造函数,它们可以容纳更多,甚至代替您最初请求的对象也可以使用更合适的对象。

您偶尔会在Python中看到工厂。 collections.namedtuple是一个很棒的,有些神奇的例子。它不只是从一个预先存在的固定列表中选择一个类,它还包括实际上,它会根据您的要求从整个布料中创建一个新类。但是,像Python,Ruby,Perl和JavaScript这样的动态语言不需要像Java这样的静态类型的语言那么频繁地使用工厂。它们的构造函数具有与Java相同的约束,但是这些语言还具有动态类型(“后期绑定”),鸭子类型以及开发人员愿意尽可能多地使用委派和继承。这些特征集为选择“适合工作的对象”提供了更大的自由度。无论是出于技术上的需要,还是出于文化选择的考虑,Java开发人员都更加依赖于
factory pattern以提高灵活性。

还应考虑历史:当今许多中间件开发人员都在Java的庞大生态系统中从技术上和经济上花费了大量时间。毫无疑问,Java的“软件工程”领域的模式和实践(例如测试,依赖项注入和子系统组成)已经扩展到其他语言社区。一旦建立了模式,期望和行话,它们就会持续存在。

因此,在技术上和其他方面,在Neutron中使用.factory()构造函数都是有意义的。

但是实际上有一个“但是...”。


我不能声称看到了世界上所有的Neutron代码,但是我看到的代码实际上并没有使用工厂。 APIRouter.factoryAPIRouter.__init__更具吸引力,呼叫顺序略有变化。与开发人员的敏感性和标准化的架构化呼叫签名保持一致-这些本身就很有价值。但这是一个狭窄的技术,因为Neutron同样可以指定标准构造函数的调用签名。当前的工厂实际上并不使用其参数或添加智能。它们是备考工厂,实际上是备用构造函数。
整个paste-deploy方法是在配置文件中指定所需的组件。这导致人们明确选择所需的类,从而限制了灵活的“我们应该构造哪种对象”的需要和价值。代码中的选择。就像动态语言的自由度使工厂脱颖而出一样,配置文件在中间件​​组合角色中削弱了工厂的价值。


关于您的第二个问题,为什么未使用配置设置?大概是因为APIRouter不需要它们。其他一些模块(例如处理版本控制和IPAM可插拔过滤器)似乎确实使用了本地或全局配置对象(尽管只是通过了)。我将未使用的配置选项归类为工厂方法:它们是组合系统的体系结构功能,实际上,该功能不被大量使用,而APIRouter恰恰是不必要的。

摘要

工厂允许更灵活地创建对象。语言越严格,以继承为重点,工厂模式就变得越有必要。作为插件框架或可扩展服务器的功能,它们非常明智。但是在这种特殊情况下,工厂的使用非常轻巧。

即使当前代码中使用的工厂不多,您也可以说它们有意义,因为外部模块或将来的版本可能会更广泛地使用。并非所有体系结构元素都需要最初用作具有价值的框架。

关于python - 为什么要在python中使用工厂方法?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/40857170/

10-16 01:02