4

我在 openstack neutron 中阅读了以下代码。

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

我在这里有两个问题。

  1. 从工厂代码我们可以知道它是用来创建APIRouter实例的。但为什么我们需要它?为什么我们不只是api_router = ApiRouter()用来获取实例?

  2. __init__和工厂中local_configglobal_config没有使用。为什么我们在函数中定义它?

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

4

1 回答 1

7

这是一个尖锐的问题。我将采取(希望是知情的)猜测。我之所以说是猜测,是因为虽然我已经查看了有问题的 OpenStack 代码,但它不是我的代码,我也没有使用这种特定的配置架构。

APIRouter()出现在源代码中是主要的实例构造函数。APIRouter.factory主要与粘贴部署设计有关,用于指定具有静态配置文件的中间件服务/处理管道。

该行业有着丰富的想象历史,即可组合模块的处理框架——插件架构非常庞大——将是构建网络服务的一种可靠、高性能的方式,并且很有可能在市场上取得成功。这个梦想至少可以追溯到1980 年代早期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(...)将做出一个“命令决定”,根据其(可能是优越的)对最佳的理解将哪个子类交回处理给定参数的实现。仍然存在耦合……但它提供了智能和价值。

这就像在餐馆里向错误的服务员要东西一样。一种可能的回答是“不!这不是我的桌子。” 没有客户对此表示赞赏。更好的回答是“Jake 是您的服务员。我会为您找他。” 这就是工厂方法可以做的事情。它们不是类的特殊方法的一部分;缺少特定的、严格的构造函数,它们可以更适应,甚至用更合适的对象代替您最初要求的对象。

你偶尔会看到 Python 中的工厂。collections.namedtuple是一个伟大的,有点神奇的例子。它不只是从预先存在的固定列表中选择一个类;它实际上根据您的规格用整块布料创建了一个新类。但是,像 Python、Ruby、Perl 和 JavaScript 这样的动态语言不需要像 Java 这样的静态类型语言那样经常需要工厂。它们的构造函数具有与 Java 相同的约束,但这些语言也具有动态类型(“后期绑定”)、鸭子类型,以及开发人员愿意使用委托和继承一样多。这组特征为选择“适合工作的对象”提供了更多的自由度。无论是技术需要还是文化选择,

还要考虑一下历史:今天的许多中间件开发人员在 Java 庞大的生态系统中无论是技术上还是经济上都花费了大量时间使用 Java。毫不奇怪,Java 在“软件工程”领域(如测试、依赖注入和子系统组合)的模式和实践已经传播到其他语言社区。一旦模式、期望和术语被确立,它们往往会持续存在。

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

但实际上有几个“但是……”。

  1. 我不能声称看到了世界上所有的 Neutron 代码,但我看到的代码实际上并没有使用工厂。APIRouter.factory比 更有吸引力APIRouter.__init__,调用顺序略有改变。与开发人员的敏感性和标准化的架构调用签名保持一致——这些本身就很有价值。但这是一个狭隘的技术性,因为 Neutron 同样可以指定标准构造函数的调用签名。当前的工厂实际上并没有使用它们的参数或添加智能。他们是备考工厂,也是事实上的替代建造者。

  2. 整个paste-deploy方法是在配置文件中指定您想要的组件。这导致人们明确地选择所需的类,限制了灵活的“我们应该构造什么样的对象?”的需求和价值。代码中的选择。正如动态语言的自由度使工厂失去了一些光彩一样,配置文件降低了工厂在中间件组合角色中的价值。

至于您的第二个问题,为什么传入的配置设置未使用?大概是因为APIRouter不需要它们。其他一些模块(例如处理版本控制和 IPAM 可插入过滤器)似乎使用本地或全局配置对象(尽管只是顺便)。我将未使用的配置选项归结为很像工厂方法:它们是组合系统的架构特性,在实践中并没有被大量使用,而对于APIRouter.

概括

工厂允许更灵活的对象创建。一种语言越是严格类型和以继承为中心的语言,工厂模式就越有必要。它们作为插件框架或可扩展服务器的功能非常明智。但在这种特殊情况下,工厂被极其轻而易举地使用。

即使工厂在当前代码中没有太多使用,您也可以认为它们是有意义的,因为外部模块或未来版本可以更广泛地使用。并非所有架构元素最初都需要作为框架的一部分才具有价值。

于 2016-11-29T04:26:15.807 回答