crazyandcoder

设计模式教程(3-工厂方法模式)

2021.07.02

工厂方法模式.png

1 定义

在工厂方法模式中,工厂父类负责定义创建产品对象的公共接口,而工厂子类则负责生成具体的产品对象,这样做的目的是将产品类的实例化操作延迟到工厂子类中完成,即通过工厂子类来确定究竟应该实例化哪一个具体产品类。

2 UML 类图

简单工厂模式包含如下角色:

(1)Factory:抽象工厂角色
负责定义创建产品对象的公共接口

(2)ConcreteFactory:具体工厂角色
工厂角色负责实现创建所有实例的内部逻辑

(3)Product:抽象产品角色
抽象产品角色是所创建的所有对象的父类,负责描述所有实例所共有的公共接口

(4)ConcreteProduct:具体产品角色
具体产品角色是创建目标,所有创建的对象都充当这个角色的某个具体类的实例。

工厂方法模式.gif

3 实现方式

3.1 抽象产品类Product

/**
 * 抽象产品
 */
public interface Product {
    void description();
}

3.2 具体产品A

public class ConcreteProductA implements Product {

    @Override
    public void description() {
        System.out.println("产品 A...");
    }
}

3.3 具体产品AA

public class ConcreteProductAA implements IProduct {

    @Override
    public void description() {
        System.out.println("产品 AA...");
    }
}

3.4 具体产品B

public class ConcreteProductB implements Product {

    @Override
    public void description() {
        System.out.println("产品 B...");
    }
}

3.5 具体产品BB

public class ConcreteProductBB implements IProduct {

    @Override
    public void description() {
        System.out.println("产品 BB...");
    }
}

3.6 抽象工厂类

/**
 * 抽象工厂类,不再负责创建具体的产品
 */
public interface IFactory {

    IProduct createProduction(String name);

    <T extends IProduct> IProduct createProduction(Class<T> clz);

}

3.7 具体工厂类A

public class ConcreteFactoryA implements IFactory {

    @Override
    public IProduct createProduction(String name) {
        if (name.equals("a")) {
            return new ConcreteIProductA();
        } else if (name.equals("aa")) {
            return new ConcreteIProductAA();
        }
        return null;
    }

    /**
     * 根据相关参数生成具体的产品
     *
     * @param clz
     * @param <T>
     * @return
     */
    @Override
    public <T extends IProduct> IProduct createProduction(Class<T> clz) {
        try {
            IProduct IProduct = (IProduct) Class.forName(clz.getName()).newInstance();
            return (T) IProduct;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

3.8 具体工厂类B

public class ConcreteFactoryB implements IFactory {

    @Override
    public IProduct createProduction(String name) {
        if (name.equals("b")) {
            return new ConcreteIProductB();
        } else if (name.equals("bb")) {
            return new ConcreteIProductBB();
        }
        return null;
    }

    /**
     * 根据相关参数生成具体的产品
     *
     * @param clz
     * @param <T>
     * @return
     */
    @Override
    public <T extends IProduct> IProduct createProduction(Class<T> clz) {
        try {
            IProduct IProduct = (IProduct) Class.forName(clz.getName()).newInstance();
            return (T) IProduct;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

测试:

public class MethodFactoryMainTest {
    public static void main(String[] args) {

        IFactory factoryA = new ConcreteFactoryA();
        IProduct productA = factoryA.createProduction(ConcreteIProductA.class);
        productA.description();


        IFactory  factoryB=new ConcreteFactoryB();
        IProduct productB = factoryB.createProduction(ConcreteIProductBB.class);
        productB.description();
    }
}

4 优缺点

4.1 优点

  1. 在工厂方法模式中,工厂方法用来创建客户所需要的产品,同时还向客户隐藏了哪种具体产品类将被实例化这一细节,用户只需要关心所需产品对应的工厂,无须关心创建细节,甚至无须知道具体产品类的类名。
  2. 基于工厂角色和产品角色的多态性设计是工厂方法模式的关键。它能够使工厂可以自主确定创建何种产品对象,而如何创建这个对象的细节则完全封装在具体工厂内部。工厂方法模式之所以又被称为多态工厂模式,是因为所有的具体工厂类都具有同一抽象父类。
  3. 使用工厂方法模式的另一个优点是在系统中加入新产品时,无须修改抽象工厂和抽象产品提供的接口,无须修改客户端,也无须修改其他的具体工厂和具体产品,而只要添加一个具体工厂和具体产品就可以了。这样,系统的可扩展性也就变得非常好,完全符合“开闭原则”。

4.2 缺点

  1. 在添加新产品时,需要编写新的具体产品类,而且还要提供与之对应的具体工厂类,系统中类的个数将成对增加,在一定程度上增加了系统的复杂度,有更多的类需要编译和运行,会给系统带来一些额外的开销。
  2. 由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度,且在实现时可能需要用到DOM、反射等技术,增加了系统的实现难度。