工厂方法模式
(Factory Method)
定义
定义一个用于创建对象的接口,让子类决定实例化哪一个类, 工厂方法使一个类的实例化延迟到其子类。
工厂方法模式的本质:延迟到子类来选择实现。
设计原则
依赖倒置原则 里氏替换原则 开闭原则
具体实现
类图
-
Product :定义工厂方法所创建的对象的接口,也就是实际需要 使用的对象接口。
-
ConcreteProduct : 具体的Product接口的实现对象。
-
FactoryMethod :创建器,声明工厂方法,工厂方法通常 会返回一个Product的实例对象,而且多是抽象方法。 也可以在Creator里面提供工厂方法的默认实现,让工厂方法返回 一个缺省的Product类型的实例对象。
-
ConcreteFactoryMethod:具体的创建器对象,返回具体的Product 实例。
客户端使用
一般客户端调用时,不直接调用 工厂方法,所以工厂方法一般 设置为 protect 的方式,仅用于子类继承实现。
客户端应该使用 非工厂方法,例如类图中的 FactoryMethod 的 getProductName() 方法。
public static void main(String[] args) {
FactoryMethod factoryMethod = new ConcreteFactoryMethod();
factoryMethod.getProductName();
}
什么时候用,适用场景
-
当你发现你的具体需要执行的方法逻辑,以后可能会进行扩展时。 例如:交费方法。存在支付宝交费,微信交费,但实际上都是交费, 只是实现不同,这种情况,便可以使用工厂方法模式。
-
如果一个类需要创建某个接口的对象,但是又不知道具体的实现。 这种情况可以使用工厂方法模式。把创建对象的工作延迟到子类中去实现。
-
如果一个类本身就希望由它的子类来创建所需的对象的时候, 应该使用工厂方法模式。
-
创建对象需要大量重复代码。
-
客户端(应用层)不依赖于产品类实例如何被创建,实现等细节。
-
客户端(应用层)只需要知道产品类由哪个工厂创建即可。
优点
-
用户只需关心所需产品对应的工厂,无须关心创建细节。
-
加入新产品符合开闭原则,提高可扩展性。
缺点
-
类的个数容易过多,增加复杂度。
-
增加了系统的抽象性和理解难度。
源码中的体现
Collection 类 的 Iterator 方法。
public interface Collection<E> extends Iterable<E> {
...// 省略
Iterator<E> iterator();
... // 省略
}
iterator 方法是 工厂方法,工厂方法需要由子类实现具体的细节。 下面再展示一下ArrayList对于 iterator 的具体实现。 ArrayList 在 iterator 方法中,返回了具体的产品类 Itr。
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable{
... // 省略
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 return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;
Itr() {}
public boolean hasNext() {
return cursor != size;
}
@SuppressWarnings("unchecked")
public E next() {
... // 省略
return (E) elementData[lastRet = i];
}
public void remove() {
... // 省略
}
@Override
@SuppressWarnings("unchecked")
public void forEachRemaining(Consumer<? super E> consumer) {
... // 省略
}
}
... // 省略
}