工厂方法模式

Factory Method

Posted by songjunhao on March 2, 2019

工厂方法模式

(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) {
            ... // 省略
        }

    }
  ... // 省略
}