工厂模式的真正优势到底在什么地方?请大家讨论
以下是我在群里和别人讨论的记录:
我:想请教一个问题:
工厂模式生成出来的产品,到底该负责由谁销毁??
请大家说说自己的想法
你说的是抽象工厂模式吗? 还是工厂方法
我:嗯...不包括单体模式.其他的所有创建型模式. 单体模式肯定不能由用户销毁的.一般也不需要销毁.呵呵
我觉得工厂方法可由用户销毁
我:飞用的什么语言?C++还是JAVA?
delphi,java c++用得少
我:对了.JAVA中NEW出来的对象,也需要DELETE么?
对象都有生命周期 面向对象编成的思想
我:原来如此.那么产品也不是由用户销毁了.是自然的结束它的生命周期了
所谓的用户是指的用户对象
我:嗯..假如由工厂负责销毁的话,那么工厂的实例将不能作为全局存在的了.
(贴子里加的:事后我想了想,即使由工厂负责销毁,工厂也是可以作为全局对象存在,只不过生成的产品数量无节制的增加)
不过更具具体需要可以变化
我:还有一点问题就是:工厂作为全局存在,就必然用到全局变量,是否有违OO原则?
可能变了之后就不仅仅是工厂模式了
我:嗯..同意.可能会是创建型里的其他模式.
oo原则里面没有说不能用全局变量呀
法则1:优先使用(对象)组合,而非(类)继承
法则2:针对接口编程,而非(接口的)实现
法则3:开放-封闭法则(OCP)
法则4:Liskov替换法则(LSP)
我:OO设计的一条经验原则是:所有数据应该隐藏在它所在的类内部 全局变量也是数据吧.
好人,用参数化工厂可以减少全局变量个数
我:参数化工厂是指的抽象工厂吧?
还是工厂方法 变种
我:噢.明白了.
参数化工厂方法
我:传入不同的参数生成不同的类型对象
对
我:不过我觉得这种把很多种互不相干的类产品集成在一个工厂里生成似乎不太好...除非这些类产品之间有继承关系 之所以使用工厂方法,目的之一就是为了让使用者不必知道要生成的类型.
对呀 没有完全完美的事情
我:...唉.也是没有办法的事了.
只不过似乎这样做,纯粹为了设计模式而设计模式.这样做与直接指定类型产生实例相比,没有任何优势,反而在效率上会有所下降. 我越来越学究了... 我去CSDN发个贴,看看大家的观点如何...
是的但是从代码的可维护性方面看可能能好一些
我:我看未必...因为生成的产品,必须指定它的类型名。比如生成一个A类产品,必须: A a = Factory.Create(A); 这与A a; 没有任何实质上的区别。 维护起来也一样麻烦。改动了Factory.Create内部返回的类型,a的类型也一样得改。 简直多此一举~ 唯一优势我看就在于Factory内产生B,C,D之类的对象,且B,C,D都继承于A 这时工厂才能发挥它的效果
其实还有一点,它可以扩展原有的工厂 TFactoryExchanged 改变创建规则
我:扩展原有的工厂改变创建规则?
对
我:不明白。举个简单例子吧
即成原有工厂,覆盖原有工厂的reate
我:生成新的产品对吧?
我:我发现经过一系列讨论后,似乎又绕回到原来的问题上去了:产品该由谁管理销毁?
"继承原有工厂,覆盖原有工厂的create
我:继承原有工厂,覆盖原有工厂的create,这种用普通的工厂模式有意义吗?我想,或许Builer更适合一些吧? 我想这不是工厂模式的优势所在。
[结束]
请大家讨论一下,对于把一大堆互不相干的类集成到一个工厂里让它为之负责生成,这种纯粹为了模式而模式的做法,有意义吗?工厂模式的真正优势所在是在哪里?我们该在什么情况下才使用工厂模式.
想不到一个简单的工厂模式竟然也有这么多问题..
问题点数:0、回复次数:10Top
1 楼jeffyan77(jeffyan77)回复于 2005-03-04 00:07:17 得分 0
quote: "把一大堆互不相干的类集成到一个工厂里让它为之负责生成,"
不相干的类不应当集中到一个工厂中,这是显然的。一个工厂应当负责生成有共同超类型的对象。
到底是否应当使用工厂,关键在于OCP原则。如果你的这些产品对象以后有可能发生变化,那么把对象的生成放到工厂中,可以把以后的变化隔离到比较小而集中的地方。相反,如果你的这些产品对象以后不可能发生变化,那么就没有必要使用工厂。这就是OCP原则的道理。
我看到很多朋友学习了设计模式,忘记了使用设计模式的目的是要达到OCP,以为是为了好看,或者其他的什么原因。这是错误的。软件工程是工程,它的考量都是非常实际的。使用设计模式是为了以后需求发生变化的时候减少修改的痛苦,就这么简单。
Top
2 楼Fusuli(傻强)回复于 2005-03-04 09:04:29 得分 0
博士讲了理论,我来加个例子吧。一个很常见的情况:数据库的切换
以.Net为例,在.Net中,访问SQLServer数据库有专用的一套SqlClient,访问Oracle数据库有专用的OracleClient,但是它们都实现了同样的接口。如果不用工厂模式,数据访问类是这样的
class EmployeeDataProvider
{
...
SqlCommand cmd = new SqlCommand();
...
}
这样的话将来要换成Oracle数据库的话就要将所有的SqlCommand换成OracleCommand,工作量可想而知,几乎是所有牵扯的数据访问的类。
如果用工厂模式:
class DataProviderFactory
{
public static IDbCommand GetNewCommand()
{
return new SqlCommand();
}
}
class EmployeeDataProvider
{
...
IDbCommand cmd = DataProviderFactory.GetNewCommand();
...
}
这样将来切换就只需要修改工厂类一个类,甚至可以通过在工厂中读取配置文件来决定返回什么类型的Command以实现切换数据库时无需重新编译程序.
Top
3 楼sunpopoapollo(e无so有)回复于 2005-03-04 09:57:58 得分 0
产品究竟该由谁管理销毁?Top
4 楼zhangA()回复于 2005-03-04 14:37:04 得分 0
垃圾回收机制Top
5 楼SInoyew(天行杨)回复于 2005-03-04 14:54:55 得分 0
传入不同的参数生成不同的类型对象。
批量优势,个体没什么优势!Top
6 楼yk84(好人(专蹭百分贴))回复于 2005-03-04 16:31:09 得分 0
对于楼上几位大虾的回答表示感谢.
不过,JAVA有垃圾回收机制,可是对于C++来说,假如传出的是一个NEW出来的指针的话,就不得不讨论到底由谁销毁了.
不知道各位是如何认为的.Top
7 楼Fusuli(傻强)回复于 2005-03-05 10:06:46 得分 0
你如果不用工厂模式是谁销毁的?Top
8 楼Fusuli(傻强)回复于 2005-03-05 10:08:32 得分 0
销毁实例和工厂模式扯不到一起Top
9 楼stonespace(stonespace)回复于 2005-03-05 12:05:30 得分 0
工厂模式只解决对象创建的问题,其实在实际开发中,只有创建对象是一个问题,销毁对象不是问题。
工厂模式解决的问题是有很多派生类的时候创建哪种派生类实例的问题,如果要针对接口编程,client支需要一个抽象类的指针,不能创建派生类的实例,所以就有了如何创建实例的问题,所以就有了工厂模式。
实例的销毁没有这个问题,不用了就删除。其实虽然client并不直接创建对象,但client调用工厂创建对象,client也知道什么时候对象不再需要用,所以一般client可以删除对象。Top
10 楼junmayang(笨猪)回复于 2005-03-06 15:27:03 得分 0
刚刚接触,谈一点点体会:便于统一管理多个实例Top




