【问题标题】:Factory pattern in Python [closed]Python中的工厂模式[关闭]
【发布时间】:2011-03-31 11:24:06
【问题描述】:

我目前正在用 Python 实现工厂设计模式,我有几个问题。

  1. 有什么方法可以防止直接实例化实际的具体类?例如,如果我有一个生成 Vehicles 的 VehicleFactory,我希望用户只使用该工厂,并防止任何人意外地直接实例化 Car() 或 Truck()。我也许可以在 init() 中抛出异常,但这也意味着工厂无法创建它的实例...

  2. 现在在我看来,工厂越来越让人上瘾。似乎一切都应该成为工厂,这样当我更改内部实现时,客户端代码不会改变。我很想知道什么时候需要使用工厂,什么时候不适合使用。例如,我可能有一个 Window 类,而现在只有一个这种类型(没有 PlasticWindow、ReinforcedWindow 或类似的东西)。在这种情况下,我是否应该为客户端使用工厂来生成 Window,以防我将来可能添加更多类型的 Windows?

  3. 我只是想知道是否有一种通常的方式来调用工厂。例如,现在我将我的 Vehicle 工厂称为 Vehicles,因此代码将类似于 Vehicles.create(...)。我看到很多教程都在做类似 VehicleFactory 的教程,但我觉得它太长了,而且有点暴露了实现。

编辑:我所说的“公开实施”的意思是它让人们知道它是一个工厂。我的感觉是客户不需要知道它是一个工厂,而是作为一个可以为你返回对象的类(当然这是一个工厂,但也许没有必要明确告诉客户?)。我知道源代码很容易暴露,所以我不是说“暴露源代码中的功能实现方式”。

谢谢!

【问题讨论】:

  • 您的命名约定非常混乱。 Vehicles 听起来像是车辆对象的集合,Vehicles.create() 听起来像是在制作 Vehicles 对象,而不是 Vehicle 对象。
  • 是的,这是真的。我会重命名它。关于我应该如何命名它的任何建议?我真的应该去 VehicleFactory 吗?
  • “让人们知道这是一家工厂”。无论如何,他们会发现的。你想保守什么秘密?为什么这个秘密如此重要?
  • 我想这里有很多误解和误解。认为我没有很清楚地表达这一点。我只是说客户不必将其视为工厂,我并不是说客户必须不知道它是工厂。这不是什么秘密。无论如何,没有问题,我将其命名为 VehicleFactory。感谢您的回复!
  • @chaindriver:有些人选名字不好;他们不使用“工厂”。您不必重复他们的错误。

标签: python design-patterns factory factory-pattern


【解决方案1】:

有什么方法可以防止直接实例化实际的具体类?

为什么?你的程序员是拒绝遵守规则的邪恶反社会者吗?如果你提供一个工厂——并且工厂做人们需要的事情——那么他们就会使用工厂。

你不能“阻止”任何事情。记住。这是 Python——他们有源代码。

我是否应该为客户端使用工厂来生成窗口,以防我将来可能添加更多类型的窗口?

嗯。不好也不坏。管理所有类层次结构和工厂细节可能会很麻烦。

添加工厂并不难。这是 Python ——你随时都有所有的源代码——你可以使用grep 来查找类构造函数,并在需要时将其替换为工厂。

由于您可以使用grep 来查找和修复错误,因此您无需像在 Java 或 C++ 中那样预先计划此类事情。

我看到很多类似 VehicleFactory 的教程,但我觉得它太长了,而且有点暴露了实现。

“太长”?它很少使用,几乎不重要。使用长名称——它可以帮助其他人理解你在做什么。这不是击键次数最少的 Code Golf。

“公开实现”?首先,它什么也不暴露。其次,这是 Python ——你随时都有所有的源代码——一切都已经暴露了。

不要再想太多关于预防和隐私的事情了。没用。

【讨论】:

  • 回复:“太长”:如果您发现自己经常输入长字,也许您需要一个支持自动完成的编辑器...
  • ...除非代码被编译,在这种情况下您无法阅读其源代码,但如果您知道如何自省,请告诉我!
  • @Beau Martínez:“除非代码被编译”?就像在 .pyc 文件中一样?它们很容易拆卸。你在说什么?
  • @chaindriver:他们不能看你的文档吗?如果他们可以阅读您有关如何使用工厂的文档,我不清楚您要防止什么。
  • @S.Lott:用户倾向于使用可用的类。假设我有 API 文档并且列出了 Vehicle 类。当用户看到它时,假设他们认为可以使用该类是合乎逻辑的。您的建议类似于说代码的任何部分都不应该检查错误,因为假设用户知道如何正确使用所有类和方法。如果是这样,就很难发现错误,因为我们没有排除某些不应该发生的情况。也许这是 Python 的方式,我猜我还不习惯。
【解决方案2】:
  1. 不要公开该类(例如将其设为私有__MyClass,或者明显不希望它直接使用_MyClass)。这种方式只能通过工厂函数实例化。
  2. 也许您应该查看关键字参数的使用和继承。听起来你可能忽略了这些,这通常会减少你对复杂工厂的依赖(说实话,我很少需要工厂)。
  3. 在 Python 中,您不能轻易防止暴露实现,它违反了Zen of Python。 (在任何语言中都是一样的,一个有决心的人最终会得到他们想要的)。最多您应该尝试确保您的代码的用户不会意外做错事,但永远不要假设知道最终用户可能决定使用您的代码实现什么目标。不要让它变得模糊和难以使用。

【讨论】:

  • 我认为第 3 点最重要。只要让做正确的事情变得简单明了,如果有人有您目前无法预见的特殊需求,那是可能的。
  • @chaindriver:遗憾的是,第 1 点是这个答案中最没用的部分。
  • 对不起,我没有再正确表达它。我的意思是,对于第 1 点,这就是我对那个特定问题所需要的确切答案。对于其他点,它们也很有用,我现在正在研究它们。谢谢!
  • @chaindriver:第 1 点是一件很糟糕的事情。从技术上讲,它是合理的。但实际上,你没有问题,也不需要这个。您正在创建一个长期存在的问题,其中包含大量损坏的 __ 类名。即使是隐藏的 _ 类名也完全是在浪费您的时间。
  • “程序员……可能不小心使用了错误的类”。正确的。 “预防”在这里没有多大帮助,不是吗?他们阅读了文档,但没有遵循它们。他们的代码会崩溃。如果你写了很多聪明的“预防”代码,会发生什么变化?它仍然在运行时崩溃。这是 Python。所有崩溃都在运行时。要么来自糟糕的编程(他们不遵守规则),要么来自良好的编程(你确保它在运行时崩溃,因为没有遵守规则。)预防不会进入它,是吗?
【解决方案3】:

Python 风格。不要使用添加不必要的抽象级别的“企业”语言(如 Java)解决方案使您的代码过于复杂。

您的代码应该简单、直观。您不需要委托给另一个类来实例化另一个类。

【讨论】:

  • +1。模式通常(尽管不总是)是 Java 等语言的遗留物。确保在 Python 中使用它们之前绝对需要它们。
  • 哦,好的,谢谢您的建议!所以我不应该寻找防止客户端代码在未来内部实现发生变化时中断的方法,例如因为添加了更多功能?这是我关心的部分。我想我太偏执了?
  • @chaindriver:方式,太偏执了。他们可以阅读您的来源。您可以采取哪些可能的“预防措施”?
  • 所以如果我只是实现我的代码而没有提前计划,那么如果我意识到一些代码需要重新组织,但我无法重新构建类,因为客户端直接实例化了类即他们的代码必须改变。在这种情况下你会怎么做? (我不是在讽刺,我只是在寻找解决这个问题的方法)
  • @chaindriver:“但我无法重组类,因为客户端直接实例化类”。假的,一般。我想你可能会制造出一种病态的情况,以至于没有前进的道路。但这很难。 “他们的代码必须改变”。嗯。你告诉他们?您提供向后兼容的替代方案?你分叉并提供一个支持的新版本和一个不支持的旧版本?这些都是简单的常见情况。看看像 Jinja 这样的开源项目,他们改用了 Jinja2。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多