什么时候使用抽象工厂模式?
Posted
技术标签:
【中文标题】什么时候使用抽象工厂模式?【英文标题】:When to use the abstract factory pattern? 【发布时间】:2011-05-18 21:18:43 【问题描述】:我试图简明扼要地描述何时为我自己和我的团队使用工厂。我遇到了以下相关问题,这在一定程度上有所帮助:
When to use factory patterns? (有用的 pdf 链接已损坏) How do you create your Factories? (更多的是“如何”而不是“何时”) What is your threshold to use factory instead of a constructor to create an object? (一些一般性答案) Factory Pattern. When to use factory methods? (更多关于工厂方法而不是工厂类) When to use Factory method pattern? (再次详细了解工厂方法)根据这些链接和一堆其他来源(列在底部),我想出了以下内容:
何时使用抽象工厂模式:
当您使用接口 var 或“新”运算符时 例如用户用户 = 新的 ConcreteUserImpl(); 并且您正在编写的代码在某些时候应该是可测试/可扩展的说明:
接口本质上意味着多种实现(有利于单元测试) 接口变量暗示符合 OCP 和 LSP 的代码(支持子类化) 使用“new”运算符会破坏 OCP/DI,因为高度耦合的类很难测试或更改“我是否为每种对象类型都创建了一个工厂?这似乎太过分了。”
不,您可以拥有一个(或几个)工厂来生产很多(通常是相关的)对象类型 例如appFactory.createUser(); appFactory.createCatalog();等等。何时不使用工厂:
新对象非常简单,不太可能被子分类 例如List list = new ArrayList(); 新对象没有兴趣测试 没有依赖关系 不执行任何相关或长期运行的工作 例如记录器 log = new SimpleLogger();参考资料:
http://googletesting.blogspot.com/2008/08/where-have-all-singletons-gone.html http://misko.hevery.com/2008/07/08/how-to-think-about-the-new-operator/ http://misko.hevery.com/2008/08/17/singletons-are-pathological-liars/ http://en.wikipedia.org/wiki/Dependency_Injection http://en.wikipedia.org/wiki/Open_Closed_Principle http://en.wikipedia.org/wiki/Liskov_substitution_principle我的问题是:我的总结是否准确,是否有意义?有什么我忽略的吗?
提前致谢。
【问题讨论】:
我讨厌恢复旧线程,但是...我不同意记录器应该像上面那样是新的。我经常在不同的测试环境中运行不同的记录器。我将环境配置为使用特定的记录器并将其注入到记录的对象中。 (我什至可以注入记录器数组。) 【参考方案1】:我还要说,当您有想要的特定实现时,不要使用工厂。继续List
示例,我知道我想要一个ArrayList
,因为我正在进行随机访问。当我可以自己做时,我不想依赖工厂来做这件事。
相反,当我不想知道具体的子类时,我可以使用工厂并让它担心实际实例化哪个对象。
我想我建议您在“何时使用抽象工厂模式”中添加一个项目符号,说明“并且您并不真正关心您获得哪个具体子类”,反之则为“何时不使用使用工厂”。
编辑:小心避免general-purpose tool-building factory factory factory。
【讨论】:
好吧 - 假设我想要缓存线程池的具体优势: ExecutorService pool = Executors.newCachedThreadPool();但是,在我的单元测试中(无论出于何种原因),我对池中完成的工作的结果不感兴趣,并且我不想每次运行测试时都必须等待工作完成。那么我不会仍然使用工厂,以便我可以存根/模拟我的线程池进行测试吗?在我看来,当您考虑测试时,您希望将大部分代码视为不关心实际实现,以免编写无法测试的代码。 是的,没错。通常,您的大部分代码都不关心实际的实现。在ArrayList
和 LinkedList
之间进行选择是您关心的少数几次之一,因为它们具有不同的性能特征。你是对的:为了测试,最好尽可能忽略实际的实现。【参考方案2】:
一般来说,当您希望能够通过外部配置切换实现时使用它。
JDBC 和 JAXP 就是很好的例子。更多示例,请查看this answer。
【讨论】:
那不是意味着使用 IoC 容器吗? 您能否详细说明何时使用自定义工厂与 IoC 来通过配置切换对象类型? @Max:取决于 API 是否要在 IoC 容器上运行。【参考方案3】:抽象工厂模式提供了一种封装具体工厂的方法,这些工厂彼此共享一些共同点,这意味着它们实现相同的接口/抽象类。
当您想要控制对象的初始化时,您需要使用工厂模式,而不是将控制权交给消费者。
【讨论】:
以上是关于什么时候使用抽象工厂模式?的主要内容,如果未能解决你的问题,请参考以下文章