创建型设计模式——工厂方法模式

定义

定义一个用于创建对象的接口,让子类决定实例化哪个类。

关键点

  • 创建型设计模式之一
  • 工厂方法模式又称工厂模式、多态工厂模式和虚拟构造器模式
  • 通过定义工厂父类负责定义创建对象的公共接口,而子类则负责生成具体的对象

《创建型设计模式——工厂方法模式》 工厂方法UML图

  • 抽象工厂(Factory),为工厂方法模式的核心
  • 具体工厂(Concrete Factory),实现了具体的业务逻辑
  • 抽象产品(Product),是工厂方法模式所创建的产品的父类
  • 具体产品(Concrete Product),为实现抽象产品的某个具体产品对象

使用场景

  • 在任何需要生成复杂对象的地方,都可以使用工厂方法模式
  • 复杂对象适合使用工厂模式,用new就可以完成创建的对象无需使用工厂模式

场景例子说明

  • 抽象产品类
public abstract class Product {
    /**
     * 抽象产品类的抽象方法
     * <br/>
     * 由具体的产品类去实现
     */
    public abstract void showProduct();
}
  • 具体产品类
// 具体产品类A
public class ProductA extends Product {
    @Override
    public void showProduct() {
        System.out.println("我是具体的产品类A");
    }
}

// 具体产品类B
public class ProductB extends Product {
    @Override
    public void showProduct() {
        System.out.println("我是具体的产品类B");
    }
}
  • 抽象工厂类
public abstract class Factory {
    /**
     * 抽象工厂方法
     * <br/>
     * 具体生产什么交给子类去做
     * @return
     */
    public abstract Product createProduct();
}
  • 具体工厂类
public class JFactory extends Factory {
    @Override
    public Product createProduct() {
        return new ProductA();
    }
}
  • 测试
public class FactoryTest {
    public static void main(String[] args) {
        Factory factory = new JFactory();
        Product product = factory.createProduct();
        product.showProduct();
    }
}

//结果
我是具体的产品类A

若是想生产产品类B,则可以将具体工厂类修改如下:

public class JFactory extends Factory {
    @Override
    public Product createProduct() {
        return new ProductB();
    }
}

// 结果
我是具体的产品类B
通过反射的方式

在我们具体的工厂中,想要生产那个具体的产品就可以生成具体的产品,但是每次都需要修改具体工厂的内容。如果采用反射的方式,则可以更为简洁地来生产具体产品。

只需要在工厂方法中的参数列表传入一个Class类来决定是哪一个产品类即可。

// 抽象工厂类
public abstract class FS_Factory {
    /**
     * 抽象工厂方法
     * <br/>
     * 具体生产什么由子类去实现
     * @param clz 产品对象类型
     * @param <T> 
     * @return
     */
    public abstract <T extends Product> T createPruduct(Class<T> clz);
}

// 具体工厂类
public class FS_JFactory extends FS_Factory {

    @Override
    public <T extends Product> T createPruduct(Class<T> clz) {
        Product product = null;
        try {
            product = (Product) Class.forName(clz.getName()).newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return (T) product;
    }

// 测试
public class FactoryTest {
    public static void main(String[] args) {
        FS_Factory fs_factory = new FS_JFactory();
        Product product1 = fs_factory.createPruduct(ProductB.class);
        product1.showProduct();

    }
}
// 结果
我是具体的产品类B

从上可以知道,通过反射可以需要哪个对象就传入哪个对象的类型即可,这种方式比较简洁、动态。

多工厂方法模式

如果觉得上述反射的方式比较复杂,不易理解,也可以尝试为每个产品单独定义具体的工厂,各司其职。这种方法被称为多工厂方法模式。

public class JFactoryA extends Factory {
    @Override
    public Product createProduct() {
        return new ProductA();
    }
}
public class JFactoryB extends Factory {
    @Override
    public Product createProduct() {
        return new ProductB();
    }
}
简单工厂模式(静态工厂模式)

假设当我们只有一个工厂,那么其实无需抽象工厂类,可以将其简化。同时将简化的工厂里的工厂方法改为静态方法即可。这种方式则被称为简单工厂模式,实际上是工厂方法模式的弱化版本。

// 简单工厂类
public class JD_Factory {
    public static Product createProduct() {
        return new ProductA();
    }
}

// 测试
public class FactoryTest {
    public static void main(String[] args) {
        Product product2 = JD_Factory.createProduct();
        product2.showProduct();

    }
}

// 结果
我是具体的产品类A

工厂方法的优缺点

优点

  • 降低了对象间的耦合性
  • 对调用者隐藏了产品的生产过程
  • 易于拓展

缺点

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

引用
《Android源码设计模式解析与实战》
Android设计模式(四)- 工厂方法模式
[Android]三种工厂模式总结。

    原文作者:忘尘无憾
    原文地址: https://www.jianshu.com/p/95cb35426bfb
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞