设计模式学习 - 工厂方法模式

设计六大原则
简单工厂模式
上篇学习了简单工厂模式,简单工厂模式的优点就是工厂类封装具体对象的实现逻辑,会根据外部传入的选择条件来判断返回对应的具体对象,也就是调用者无需关心内部实现逻辑,只需传入所需对象的类型即可,同样的缺点也很明显,如果要通过工厂类的获取所需的具体对象,必须在工厂类中的静态方法先定义该类型才行,如果新增了类型,就要修改此前的静态方法中的判断语句,需要增加一个if或者case语句,来定义新类型,这样才能获取到新类型的具体对象,这就违背了设计模式的开放封闭原则

工厂方法模式的引入就是解决简单工厂模式的缺陷,与此同时,工厂方法模式也继承了简单工厂模式的优点。

工厂方法模式简介

定义

定义一个用于创建对象的接口(或者抽象类),让子类实现接口或者继承抽象类,最后决定实例化哪个类。工厂方法使一个类的实例化延迟到其子类。

UML类结构图

这里写图片描述

  • Product:抽象类或者接口
  • ConcreteProduct:具体产品类,实现了Product接口(或者继承Product抽象类)
  • Creator:抽象工厂类,重写该方法会返回一个Product类型的对象。
  • ConcreteCreator:具体工厂类,继承于抽象工厂类,实现了抽象类中方法并返回一个ConcreteProduct实例。

工厂方法模式实现

使用步骤

使用步骤与简单工厂模式类型,只不过多出了一个抽象工厂类及实现类。在定义的抽象工厂需要用到泛型和反射。

  1. 创建抽象类或者接口,定义需要的方法。
  2. 创建具体产品类,继承于抽象类或实现接口。
  3. 创建抽象工厂类,定义带返回类型的抽象方法。
  4. 创建具体工厂类,继续于抽象工厂类,实现抽象方法。
  5. 外部调用,先实例化具体工厂类,调用具体工厂类中的方法并传入产品类的Class类对象,并可获取具体产品类的实例。

例子

具体实例场景,还在以简单工厂模式中的玩具场景为准。

1、创建抽象类,定义生产玩具的方法

public abstract class Product {

    public abstract void created();

}

2、创建具体产品类,用于实现玩具的生产。

public class CarProduct extends Product{

    @Override
    public void created() {
        System.out.println("玩具汽车已经生产完毕");
    }

}

public class AircraftProduct extends Product{

    @Override
    public void created() {
        System.out.println("玩具飞机已经生产完毕");
    }

}


public class TrainProduct extends Product{

    @Override
    public void created() {
        System.out.println("玩具火车已经生产完毕");
    }

}

3、创建抽象工厂类,定义带返回Product类型的抽象方法。

public abstract class ToyProductFactory {

    /**
     * 
     * 定义带返回值一个泛型方法,用于创建各种各样的玩具产品
     * @param clazz 产品类的Class类对象
     * @param clientType 客户类型,方便测试
     * @return 返回一个Product类型的对象
     */
    public abstract <T extends Product>T createToyProduct(Class<T> clazz,String clientType);

}

4、创建具体工厂类,继承于ToyProductFactory类,并实现该抽象工厂类的方法。

public  class HZWToyProductFactory extends ToyProductFactory{

    @Override
    public <T extends Product> T createToyProduct(Class<T> clazz,String clientType) {
        Product product=null;
        try {
            //通过反射获取具体实例对象
            product = clazz.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        } 
        //为了方便测试观察,加入了客户类型并输出
        System.out.println(clientType);
        //调用Product对象的created方法,输出客户需要的玩具产品
        product.created();

        System.out.println("---------------");
        return (T) product;
    }

}

5、创建HZWToyProductFactory实例,并调用createToyProduct方法,传入客户需要的玩具产品及客户类型即可生产对应的玩具。

HZWToyProductFactory productFactory = new HZWToyProductFactory();
CarProduct carProduct = productFactory.createToyProduct(CarProduct.class, "客户1");
productFactory.createToyProduct(TrainProduct.class, "客户2");
productFactory.createToyProduct(AircraftProduct.class, "客户3");
productFactory.createToyProduct(AircraftProduct.class, "客户4");

最后运行结果如下:

客户1
玩具汽车已经生产完毕
---------------
客户2
玩具火车已经生产完毕
---------------
客户3
玩具飞机已经生产完毕
---------------
客户4
玩具飞机已经生产完毕
---------------

从上面可知,不管客户类型新增多少,都可以生产客户想要的玩具产品,不用再去修改之前的工厂类来满足新客户的要求。

在定义抽象工厂时使用了反射和泛型,如何要使用反射和泛型,主要有以下优势:
在未知类型的情况下,可以通过反射动态类加载得到具体实例,比如每个客户需要的玩具产品都不一样。而泛型是避免强制类型转换异常的出现。

泛型与反射具体应用


感谢:
《大话设计模式》、《Android进阶之光》

猜你喜欢

转载自blog.csdn.net/hzw2017/article/details/80753899