工厂方法(Factory Method)
Intent
定义了一个创建对象的接口,但由子类决定要实例化哪个类。工厂方法把实例化操作推迟到子类。
Class Diagram
在简单工厂中,创建对象的是另一个类,而在工厂方法中,是由子类来创建对象。
下图中,Factory 有一个 doSomething() 方法,这个方法需要用到一个产品对象,这个产品对象由 factoryMethod() 方法创建。该方法是抽象的,需要由子类去实现。

Implementation
public abstract class Factory {abstract public Product factoryMethod();public void doSomething() {Product product = factoryMethod();// do something with the product}}
public class ConcreteFactory extends Factory {public Product factoryMethod() {return new ConcreteProduct();}}
public class ConcreteFactory1 extends Factory {public Product factoryMethod() {return new ConcreteProduct1();}}
public class ConcreteFactory2 extends Factory {public Product factoryMethod() {return new ConcreteProduct2();}}
工厂方法模式总结
工厂方法模式是简单工厂模式的延伸,它继承了简单工厂模式的优点,同时还弥补了简单工厂模式的不足。工厂方法模式是使用频率最高的设计模式之一,是很多开源框架和API类库的核心模式。
工厂方法模式的主要优点
- 在工厂方法模式中,工厂方法用来创建客户所需要的产品,同时还向客户隐藏了哪种具体产品类将被实例化这一细节,用户只需要关心所需产品对应的工厂,无须关心创建细节,甚至无须知道具体产品类的类名。
- 基于工厂角色和产品角色的多态性设计是工厂方法模式的关键。它能够让工厂可以自主确定创建何种产品对象,而如何创建这个对象的细节则完全封装在具体工厂内部。工厂方法模式之所以又被称为多态工厂模式,就正是因为所有的具体工厂类都具有同一抽象父类。
使用工厂方法模式的另一个优点是在系统中加入新产品时,无须修改抽象工厂和抽象产品提供的接口,无须修改客户端,也无须修改其他的具体工厂和具体产品,而只要添加一个具体工厂和具体产品就可以了,这样,系统的可扩展性也就变得非常好,完全符合”开闭原则”。
工厂方法模式的主要缺点
在添加新产品时,需要编写新的具体产品类,而且还要提供与之对应的具体工厂类,系统中类的个数将成对增加,在一定程度上增加了系统的复杂度,有更多的类需要编译和运行,会给系统带来一些额外的开销。
由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度,且在实现时可能需要用到DOM、反射等技术,增加了系统的实现难度。
适用场景
客户端不知道它所需要的对象的类。在工厂方法模式中,客户端不需要知道具体产品类的类名,只需要知道所对应的工厂即可,具体的产品对象由具体工厂类创建,可将具体工厂类的类名存储在配置文件或数据库中。
- 抽象工厂类通过其子类来指定创建哪个对象。在工厂方法模式中,对于抽象工厂类只需要提供一个创建产品的接口,而由其子类来确定具体要创建的对象,利用面向对象的多态性和里氏代换原则,在程序运行时,子类对象将覆盖父类对象,从而使得系统更容易扩展。
工厂方法模式的典型应用及源码分析
Java集合接口 Collection 中的工厂方法模式
Collection 中的 iterator 方法如下:
关于 iterator 方法的介绍: Java的迭代器只在Collection中有,而Map没有迭代器,它有不同的迭代方法;public interface Collection<E> extends Iterable<E> {Iterator<E> iterator();// ...省略}
迭代器的终极目标:就是用统一的方法来迭代不同类型的集合!可能由于不同集合的内部数据结构不尽相同,如果要自己纯手工迭代的话相互之间会有很大的差别,而迭代器的作用就是统一的方法对不同的集合进行迭代,而在迭代器底层隐藏不同集合之间的差异,从而为迭代提供最大的方便 使用用迭代器迭代的步骤: i. 第一步肯定是先获取集合的迭代器:调用集合的iterator方法就能获得,IteratorCollection.iterator(); ii. 使用迭代器的hasNext、next往下迭代
Iterator的常用方法:boolean hasNext():是否还有下一个元素; Object next():取出下一个元素并返回; void remove(); :从容器中删除当前元素,直接会改变容器中的数据
查看该接口的实现类,可以看到是非常的多
Collection接口的实现类(部分)
我们仅看其中一个实现类 java.util.ArrayList,看其对 iterator 方法的实现
Itr 类实现了 iterator 接口,iterator 接口正是 Collection 接口中 iterator 方法的返回类型,其代码如下:public Iterator<E> iterator() {return new Itr();}/*** An optimized version of AbstractList.Itr*/private class Itr implements Iterator<E> {int cursor;// index of next element to returnint lastRet = -1;// index of last element returned; -1 if no suchint expectedModCount = modCount;Itr() {}public boolean hasNext() {return cursor != size;}@SuppressWarnings("unchecked")public E next() {// ...省略...}public void remove() {// ...省略...}@Override@SuppressWarnings("unchecked")public void forEachRemaining(Consumer<? super E> consumer) {// ...省略...}final void checkForComodification() {// ...省略...}}
由此可见,Collection 接口扮演了抽象工厂角色,工厂方法为 iterator(),Collection 的实现类譬如 ArrayList 扮演了具体工厂角色,而抽象产品为 Iterator 接口,具体产品为 Itr 类public interface Iterator<E> {boolean hasNext();E next();default void remove() {throw new UnsupportedOperationException("remove");}default void forEachRemaining(Consumer<? super E> action) {Objects.requireNonNull(action);while (hasNext())action.accept(next());}}
