工厂方法模式(Factory Method Pattern)

1,489 阅读8分钟

在设计模式中按照不同的处理方式共包含三大类:创建型模式、结构型模式和行为模式。

创建型模式

  1. 工厂方法模式(Factory Method Pattern)
  2. 抽象工厂模式(Abstract Factory Pattern)
  3. 建造者模式(Builder Pattern)
  4. 原型模式(Prototype Pattern)
  5. 单例模式(Singleton Pattern)

在介绍工厂方法模式之前可以先看看简单工厂模式

简单工厂模式(Simple Factory Pattern)

简单工厂模式是属于创建型模式,又叫做静态工厂方法(Static Factory Method)模式,但不属于23种GOF设计模式之一。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。简单工厂模式是工厂模式家族中最简单实用的模式,可以理解为是不同工厂模式的一个特殊实现。

简单工厂模式的实质是由一个工厂类根据传入的参数,动态决定应该创建哪一种产品(这些产品类继承自一个父类或接口)的实例。

该模式中包含的角色和职责

工厂(Factory)角色

简单工厂模式的核心,它负责实现创建所有实例的内部逻辑。工厂类的创建产品类的方法可以被外界直接调用,创建所需的产品对象。

抽象(Product)产品角色

简单工厂模式所创建的所有对象的父类,它负责描述所有实例所共有的公共接口。

具体产品(Concrete Product)角色

是简单工厂模式的创建目标,所有创建的对象都是充当这个角色的某个具体类的实例。

实例的的UML图

image.png

下面是具体的代码

抽象(Product)产品角色

/**
 * 笔类接口
 */
public interface Pen {
    void write();
}

具体产品(Concrete Product)角色

/**
 * 圆珠笔
 */
public class BallpointPen implements Pen {
    @Override
    public void write() {
        System.out.println("书写:我是圆珠笔!");
    }
}
/**
 * 铅笔
 */
public class Pencil implements Pen {
    @Override
    public void write() {
        System.out.println("书写:我是铅笔!");
    }
}
/**
 * 马克笔
 */
public class MarkerPen implements Pen {
    @Override
    public void write() {
        System.out.println("书写:我是马克笔!");
    }
}

工厂(Factory)角色

/**
 * 创建笔工厂
 * */
public class SimpleFactory {
    public static Pen getPen(String type) {
        switch(type){
            case "BallpointPen":return new BallpointPen();
            case "MarkerPen":return new MarkerPen();
            case "Pencil":return new Pencil();
            default:break;
        }
        return new Pencil();
    }
}

另外一种工厂(Factory)角色

/**
 * 创建笔工厂
 * */
class SimpleFactoryTwo {
    private static final Map<String,Pen> PEN_MAP = new HashMap<>();
    static {
        PEN_MAP .put("BallpointPen",new BallpointPen());
        PEN_MAP .put("MarkerPen",new MarkerPen());
        PEN_MAP .put("Pencil",new Pencil());
    }
    public static Pen getPen(String type) {
        return PEN_MAP .get(type);
    }
}

测试类

/**
 * @author yangqiang
 */
public class PenWithType {

    public static void main(String[] args) {
        Pen ballpointPen = SimpleFactory.getPen("BallpointPen");
        ballpointPen.write();
        Pen pencil = SimpleFactory.getPen("Pencil");
        pencil.write();
        Pen markerPen = SimpleFactory.getPen("MarkerPen");
        markerPen.write();
    }

}

由上面的实例可见 简单工厂模式的概念是:
客户端通过工厂类去进行对象的创建和获取。根据传入不同的类型工厂类返回给客户端需要的具体产品。然后进行消费

优点

  • 工厂类包含必要的逻辑判断。可以根据客户端传入的类型来进行创建不同的对象。免去客户端创建对象的职责。工厂类创建对象。客户端消费对象。符合单一职责。
  • 可以通过引入配置文件 。在不改变客户端的情况下添加具体产品

缺点

  • 创建具体产品对象的职责都在工厂类中,一旦工厂类出现异常,整个系统都会受到影响。
  • 使用简单工厂模式将会增加系统中类的个数,在一定程序上增加了系统的复杂度和理解难度。
  • 系统扩展困难。增加了新的具体产品时。都需要修改工厂类的代码逻辑。不符合开闭原则。具体产品数量过多时,可能会造成工厂类逻辑复杂,不利于系统的维护和扩展

适用场景

  • 工厂类负责创建对象的数量很少。不会造成工厂类整个代码逻辑复杂
  • 客户端完全不关心对象的创建。只知道对应具体产品创建的类型。具体对象类名也不清楚

工厂方法(FactoryMethod)模式

在我们详述工厂方法模式的概念之前,我们先对以上的简单工厂模式的例子进行一个改造。 对于具体类及具体类的接口,我们不做修改,保持原来的代码不动

抽象工厂(Factory)角色

public interface Factory {
    Pen getPen();
}

具体工厂(Factory)角色

/**
 * 圆珠笔工厂
 */
public class BallpointPenFactory implements Factory {
    @Override
    public Pen getPen() {
        return new BallpointPen();
    }
}

/**
 * 铅笔工厂
 */
class PencilFactory implements Factory {
    @Override
    public Pen getPen() {
        return new Pencil();
    }
}

客户端

/**
 * @author yangqiang
 */
public class PenFactoryMethod {
    public static void main(String[] args) {
        new BallpointPenFactory().getPen().write();
        new PencilFactory().getPen().write();
    }
}

我们上面示例的实现就是一个工厂方法模式的一个简单实现,通过对简单工厂模式的改造,我们可以发现在工厂方法模式中,我们不再提供一个统一的工厂类来创建所有具体类的实例对象,而是针对不同的具体类实现了不同的工厂,系统提供了一个与具体类相同等级的工厂等级结构。

工厂方法模式的构成

  • 具体类型的公共接口(Pen)或父类
  • 具体实现类(Pencil、BallpointPen )
  • 工厂接口(Factory)
  • 具体工厂(BallpointPenFactory、PencilFactory)

UML图

image.png

工厂方法模式是简单工厂模式的衍生,解决了许多简单工厂模式的问题。首先完全实现‘开-闭 原则’,实现了可扩展。其次更复杂的层次结构,可以应用于产品结果复杂的场合。

工厂方法模式对简单工厂模式进行了抽象。有一个抽象的Factory类(可以是抽象类和接口),这个类将不再负责具体的产品生产,而是只制定一些规范,具体的生产工作由其子类去完成。在这个模式中,工厂类和产品类往往可以依次对应。即一个抽象工厂对应一个抽象产品,一个具体工厂对应一个具体产品,这个具体的工厂就负责生产对应的产品。

工厂方法模式(Factory Method pattern)是最典型的模板方法模式(Template Method pattern)应用。

工厂方法模式是简单工厂模式的延伸,它继承了简单工厂模式的优点,弥补了简单工厂模式的缺点。工厂方法模式是使用频率最高的设计模式之一, 是很多开源框架和API类库的核心模式。

package org.springframework.aop.framework;

import org.aopalliance.intercept.Interceptor;

import org.springframework.aop.TargetSource;
import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;


@SuppressWarnings("serial")
public class ProxyFactory extends ProxyCreatorSupport {

  
   public ProxyFactory() {
   }

 
   public ProxyFactory(Object target) {
      setTarget(target);
      setInterfaces(ClassUtils.getAllInterfaces(target));
   }


   public ProxyFactory(Class<?>... proxyInterfaces) {
      setInterfaces(proxyInterfaces);
   }


   public ProxyFactory(Class<?> proxyInterface, Interceptor interceptor) {
      addInterface(proxyInterface);
      addAdvice(interceptor);
   }


   public ProxyFactory(Class<?> proxyInterface, TargetSource targetSource) {
      addInterface(proxyInterface);
      setTargetSource(targetSource);
   }


   /**
   * 动态的去获取一个代理对象这个代理对象由 createAopProxy() 去返回
   */
   public Object getProxy() {
      return createAopProxy().getProxy();
   }


   public Object getProxy(@Nullable ClassLoader classLoader) {
      return createAopProxy().getProxy(classLoader);
   }


   /**
   * 生产一个代理对象
   */
   @SuppressWarnings("unchecked")
   public static <T> T getProxy(Class<T> proxyInterface, Interceptor interceptor) {
      return (T) new ProxyFactory(proxyInterface, interceptor).getProxy();
   }


   @SuppressWarnings("unchecked")
   public static <T> T getProxy(Class<T> proxyInterface, TargetSource targetSource) {
      return (T) new ProxyFactory(proxyInterface, targetSource).getProxy();
   }


   public static Object getProxy(TargetSource targetSource) {
      if (targetSource.getTargetClass() == null) {
         throw new IllegalArgumentException("Cannot create class proxy for TargetSource with null target class");
      }
      ProxyFactory proxyFactory = new ProxyFactory();
      proxyFactory.setTargetSource(targetSource);
      proxyFactory.setProxyTargetClass(true);
      return proxyFactory.getProxy();
   }

}

ProxyFactory 代理工厂里面有很多getProxy的方法 ProxyFactory 生产的代理对象可以是静态一个 new出来的对象。也可以是一个抽象的接口AopProxy

优点

  • 在工厂方法模式中,工厂方法用来创建具体类的实例,同时向客户隐藏了具体类实例化的细节,用户只需要关心具体类对应的工厂,无需关心实例创建的细节以及甚至不需要关心具体类的类名,实现具体类与用户之间的解耦。
  • 基于工厂接口和具体类型的公共接口的多态性设计是工厂方法模式的关键。它能够让工厂能够自主确定创建何种具体实现类的对象,但是具体对象的创建细节又封装到了具体工厂的内部。工厂方法模式被称为多态工厂模式,就正是因为所有的具体工厂类都有一个公共的接口或者父类。
  • 使用工厂方法模式的另外一个优点就是在系统中加入新的具体类时,无需修改原有的代码,只需要增加新类的实现以及新类对应的工厂即可,完全符合“开闭原则”。

缺点

  • 添加新的具体实现类时,需要添加对应的工厂类,系统中的类的个数会成对增加,在一定程度上增加了系统的复杂度;类的增多就有更多的类需要编译,增加系统的开销。
  • 由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度,且在实现时可能需要用到DOM、 反射等技术,增加了系统的实现难度。

适用场景

客户端不需要知道它所需要的对象的类。在工厂方法模式中,客户端不需要知道具体类的类名,只需要知道它的工厂即可,具体类的实例由工厂创建。