工厂方法模式属于创建模式,也是关于如何创建对象的模式。是对简单工厂模式的改进。简单模式中工厂处于核心位置,对于复杂的层次对象显得过于复杂,缺乏扩展性。即做不到“开-闭”原则。如果有新产品加入到系统,需要须改工厂,加入创建逻辑。工厂模式则巧妙的避开了这点,并且把创建责任推迟到子类。
另外,工厂方法的这个技术(虚拟创建推迟到子类)对开发系统框架非常有用。
1.工厂方法模式中涉及的角色
抽象工厂,具体工厂,抽象产品, 具体产品。
把简单工厂中的工厂对象分派成多个具体工厂,每一个具体工厂负责创建一个具体的产品。和客户端直接创建具体产品相比较,运用工厂方法做到了对客户端透明,即客户端得到的一个抽象产品的具体实例,而不需要明确的知道真正的具体产品。同时克服了简单工厂的开闭原则问题。做到了有新产品加入无需修改工厂核心类,只需要新加入具体工厂即可。给人感觉上隐藏了对体的产品,但却暴露了具体的工厂,使得一个具体产品对应一个具体工厂,但实际上大多数情况这些具体工厂可能是由客户端本身去定义创建的,所以也比较合理。
2. 工厂方法模式使用的前提
1> 有创建一批有相同接口对象的需求
2> 不想暴露太多类的细节给使用者,或者隐藏对象的创建工作
1> 产品的等级机构比较复杂,使用简单工厂模式可能会造成扩展性问题。
4> 当一个类不知道他必须创建的类的时候,或者一个类希望由他的子类制定他所创建的对象的时候。举个例子:系统框架使用抽象类定义,创建和维护对象之间的关系,但通常这些具体的类需要有客户端来具体化,对于框架无法知道具体子类的情况下,使用工厂模式来进行框架的开发维护。所以,工厂模式也被称作“虚拟构造器”
所以对于使用工厂方法模式优化简单工厂模式,如:在聚集中Collection工厂方法iterator()返回Iterator对象,Collection其实就是抽象工厂,Iterator就是抽象产品,每个派生于Collection的聚集对象必须实现iterator()返回自己具体的Iterator实现,如ArrayList。其中每个子聚集类就是具体工厂,他们自己实现如何返回抽象对象,对客户端来说返回的产品还是透明的抽象产品。
客户端此时需要创建具体的工厂,如具体的聚集对象ArrayList,Hashtable等具体工厂,其实这些对象主要工作是容器,至于作为具体工厂只是其一个小功能,所以直接暴露很多具体工厂这里也是ok的。其实如果一个接口A返回另一个接口或者抽象对象B,可以说这个接口A是一个抽象工厂,实现这个接口的类是具体工厂。这么一说,是不是感觉我们平时很多地方已经自觉不自觉地运用了工厂模式呢?哈哈
其实个人认为,工厂方法模式如果处理上述的第4类问题,可能更像是工厂方法。比如:一个文档处理框架,中有抽象的Application负责整个文档的管理,Document为一个抽象的文档,我们需要管理整个文档的流程,比如文档的新建,等等,这样我们需要知道具体的文档类了,但其实我们是无法知道我们的User到底会创建什么类,此时工厂方法模式就派上了用场。
我们在抽象的Application中定义了工厂方法:CreateDocument();这样在具体的子类中就可以具体实现如何创建了。此时我们在Application就可以完成我们的框架如OpenDocument(),NewDocumet()等这类工作了。
3.工厂方法模式的优点缺点
优点:
1> 优化了简单工厂模式,做到了“开-闭”原则。
2> 可以做到把具体的产品创建过程延迟的具体的子类工厂,使得基类工厂可以基于工厂方法创建的抽象对象工作。
缺点:
1> 暴露具体工厂,但多数情况这不会造成问题,尤其是对于虚拟构造器,就显得更加合理。
4.备注