这让我困扰了一段时间,如果这是一个神话,我没有任何线索。
似乎工厂模式可以减轻为类添加依赖项的痛苦。
例如,在一本书中,它有类似的东西
假设您有一个名为Order的类。最初它并不依赖于任何东西。因此,您不必费心使用工厂来创建Order对象,而您只是使用plain new来实例化对象。但是,您现在要求必须与客户关联创建订单。您需要更改百万个位置才能添加此额外参数。如果你只为Order类定义了一个工厂,那么你就可以满足新的要求而不会有同样的痛苦。
与构造函数中添加额外参数有何不同?我的意思是你仍然需要为工厂提供一个额外的参数,并且还有百万个地方使用,对吗?
答案 0 :(得分:5)
如果当时只知道用户,则创建订单,您可以实现工厂调用的getCurrentUser()
功能。
如果可能,工厂功能显然会胜出。如果没有,那就没有收获。
如果在过去,您不知道客户需要什么,您可能也不知道是否可以实现getCurrentUser()
功能。 工厂方法获得回报的可能性可能不是很好,但它们并不总是等于0.
答案 1 :(得分:3)
使用工厂的真正好处在于它是一个外观,它隐藏了如何创建满足Order角色的对象。更确切地说,工厂知道你真的正在制作一个FooBarOrder,并且不需要改变任何其他东西来改变从总是制作FooBarOrder到有时候制作BarFooOrder。 (如果Java允许你拦截new
并改为创建一个子类,那么就不需要工厂了。但是它没有 - 相当合理,公平 - 所以你必须拥有它们。允许子类化的对象系统在这方面,班级更灵活。)
答案 2 :(得分:2)
不,因为工厂的依赖项应该通过工厂构造函数注入,并且您只在一个地方构建工厂,但是将它作为依赖项传递给需要创建订单的所有内容。从工厂获得订单的东西仍在调用相同的方法,CreateOrder()或其他任何东西,以便代码保持不变。
依赖关系应该全部连接在一个地方,composition root,这应该是唯一需要更改的地方,以便将新的依赖项添加到工厂
答案 3 :(得分:1)
您告诉工厂新的依赖关系,并让它为您添加。对工厂的方法调用应保持不变。
答案 4 :(得分:1)
The factory pattern可以减轻添加依赖项的痛苦,因为工厂可能包含状态,实际上,可以封装多个依赖项(例如,而不是提供三个依赖项,所有这些都需要调用某个对象的构造函数,现在只提供一个工厂对象,其中工厂包含需要提供给构造函数的那三个对象。)
举个例子,比较:
void DoIt(const DependencyA& a, const DependencyB& b) {
// NOTE: "x" is a contrived additional variable that we add here to
// justify why we didn't just pass DependencyC directly.
int x = ComputeX();
std::unique_ptr<DependencyC> dependency_c(new DependencyC(a, b, x));
dependency_c->DoStuff();
}
和
void DoIt(const DependencyCFactory& factory) {
int x = ComputeX();
std::unique_ptr<DependencyC> dependency_c(factory->Create(x));
dependency_c->DoStuff();
}
请注意,第二个版本对方法“DoIt”的依赖性较少。这并不意味着在整个程序中不需要那些依赖项(实际上,程序仍然在工厂的实现中使用DependencyA和DependencyB)。但是,通过这种方式构造它,该依赖关系可以被隔离到工厂代码,这使得其他代码更简单,更容易更改DependencyC
的依赖关系(现在只需要工厂本身,需要更新,并非每个实例化DependencyC
)的地方,甚至可以具有某些安全/安全性好处(例如,如果DependencyA
和DependencyB
是敏感的,例如数据库密码或API密钥,则限制它们的使用与你在需要使用数据库或API的所有地方传递这些错误处理的情况相比,工厂减少了误操作的可能性。
在本书给出的例子中,为Order
设置工厂的原因是它会减少直接使用构造函数的地方数量;只需要修改创建工厂的一个地方就可以将Customer
存储为工厂的附加字段;工厂的其他用途都不需要修改。相比之下,在不使用工厂的情况下,构造函数的直接使用比比皆是,并且必须更新它们中的每一个以某种方式获得对Customer
对象的访问权。