简单工厂设计模式&lambda重构简单工厂模式

概念以及背景
简单工厂模式(Simple Factory Pattern):定义一个工厂类,它可以根据参数的不同返回不同类的实例,被创建的实例通常都具有共同的父类。
因为在简单工厂模式中用于创建实例的方法是静态(static)方法,因此简单工厂模式又被称为静态工厂方法(Static Factory Method)模式,它属于类创建型模式。
工厂模式是最常用的一类创建型设计模式,通常我们所说的工厂模式是指工厂方法模式而简单工厂模式并不属于GoF 23个经典设计模式,但通常将它作为学习其他工厂模式的基础。

简单地说就是需要什么对象,传入给定格式的参数,就可以获取所需对象,而调用方无需知道其中创建对象的细节,在创建对象那一方也有自己的实现细节,代码结构清晰、解耦。

本文涉及源码在这里

里面用三种不同的方式应用了简单工厂模式,有用到Java8 Lambda 方式重构简单工厂模式,也有一个我实际开发中应用到的方式。

一、简单工厂模式

UML类图如下,有一个抽象金融产品类AbstractFinanceProduct,有三个子类,贷款(LoanFinanceProduct)、股票(StockFinanceProduct)和债券(BondFinanceProduct)都是抽象金融产品类(AbstractFinanceProduct)的子类。
工厂类是SimpleFactory,负责建对象,根据传入的参数,返回需要的对象。


/**
 * 抽象金融产品类
 */
public abstract class AbstractFinanceProduct {

    /**
     * 所有产品类的公共业务方法
     */
    public void methodSame() {
        String className = this.getClass().getName();
        //公共方法的实现
        System.out.println("抽象类公共方法,该类是:" + className);
    }

    /**
     * 声明抽象业务方法
     */
    public abstract void disPlayProduct();
}

产品名称枚举,用于工厂类创建对象方法的参数,用枚举的话比用常量好,常量的话方法参数调用方可能会给超出产品范围的常量,而用枚举的话产品枚举类范围都是明确的,也不用担心写错,如把股票Stock写成Stick等错误写法。

/**
 * 产品名称枚举
 */
public enum ProductEnum {
    /**
     * 产品类别
     */
    Bond("Bond"), Loan("Loan"), Stock("Stock");

    String name;

    ProductEnum(String name) {
        this.name = name;
    }
}
/**
 * 简单工厂类
 */
class SimpleFactory {

    static AbstractFinanceProduct creatProduct(ProductEnum productEnum) {
        switch (productEnum) {
            case Bond :
                return new BondFinanceProduct();
            case Loan :
                return new LoanFinanceProduct();
            case Stock :
                return new StockFinanceProduct();
            default:
                throw new RuntimeException("No such product" + productEnum.name());
        }
    }
}

工厂类的调用方,只需传入某个产品的类别,即可返回该产品对象。

public class SimpleFactoryPattern {
    public static void main(String[] args) {
        AbstractFinanceProduct stockProduct = SimpleFactory.creatProduct(ProductEnum.Stock);
        AbstractFinanceProduct bondProduct = SimpleFactory.creatProduct(ProductEnum.Bond);
        stockProduct.methodSame();
        stockProduct.disPlayProduct();
        bondProduct.disPlayProduct();
    }
}
二、用Java8 Lambda重构简单工厂模式

跟步骤一的UML类图一样,如下:


用lambda的方式实现简单工厂模式,lambda给我们提供了一些常用的函数式接口可以用,简单工厂模式需要建对象和返回对象,故可用Supplier<T>函数式接口,至于创建所需对象的入参,接着下面看。

@FunctionalInterface
public interface Supplier<T> {
    /**
     * Gets a result.
     *
     * @return a result
     */
    T get();
}

这里把所需创建对象的入参做成一个Map的key键,而Map的value是一个函数式接口,在设值的时候用lambda实现该value的函数式接口,这里巧妙地用了lambda的方法引用ClassName::new,实现函数式接口Supplier<T>的get()接口方法。

/**
 * 用lambda的方式实现简单工厂模式
 */
class SimpleFactoryLambda {
    /**
     * Map的value是一个函数式接口,里面的接口待实现
     */
    private final static Map<ProductEnum, Supplier<AbstractFinanceProduct>> PRODEUC_MAP = new HashMap<>();
    static {
        //这里put进去的value就是函数式接口的一个实现,lambda表达式的方法引用
        PRODEUC_MAP.put(ProductEnum.Bond, BondFinanceProduct::new);
        PRODEUC_MAP.put(ProductEnum.Stock, StockFinanceProduct::new);
        PRODEUC_MAP.put(ProductEnum.Loan, LoanFinanceProduct::new);
    }

    static AbstractFinanceProduct creatProduct(ProductEnum productEnum) {
        Supplier<AbstractFinanceProduct> productSupplier = PRODEUC_MAP.get(productEnum);
        if (productSupplier != null) {
            //这里每次调用都生成新的对象,map的value得到的是一个函数式接口的lambda实现,每次都new新对象出来。
            return productSupplier.get();
        }
        throw new IllegalArgumentException("No such product" + productEnum.name());
    }
}
三、开发中的应用简单工厂模式的例子

如果不想所创建的对象都是子类继承父类,高度耦合的(实际也很少这样),但在实际开发中又需要经常用到创建对象,可以试试下面这种方式。
这个是我在开发中所运用到的,项目需要大量调用淘宝的接口,淘宝请求参数的对象又有不同的属性,即调用淘宝线上不同的接口,都需要有不同的入参对象DTO,所以这些对象都不是继承的关系,这里用简单工厂模式来建请求淘宝接口的对象。
UML类图:


/**
 * 请求报文,T 携带简单工厂所创建的不同对象
 * @author Fiuty
 */
public class RequestDTO <T>{
    private T payload;

public class Animal {

    private String name;

    public Animal(String name) {
        this.name = name;
    }

public class People {

    private String name;

    public People(String name) {
        this.name = name;
    }
}

工厂接口类,建对象的方法,统一返回RequestDTO<T>,在泛型中返回所需的对象,而这些对象都不是子类继承父类,高度耦合。

public interface SimpleFactoryAdvanceService {

    RequestDTO<People> createPeople(String name);

    RequestDTO<Animal> createAnimal(String name);
}

工厂实现类

public class SimpleFactoryAdvanceServiceImpl implements SimpleFactoryAdvanceService {

    @Override
    public RequestDTO<People> createPeople(String name) {
        return new RequestDTO<>(new People(name));
    }

    @Override
    public RequestDTO<Animal> createAnimal(String name) {
        return new RequestDTO<>(new Animal(name));
    }
}

最后调用工厂实现类来生产我们所需的对象:

public class SimpleFactoryPatternAdvance {

    public static void main(String[] agrs) {
        SimpleFactoryAdvanceServiceImpl factory = new SimpleFactoryAdvanceServiceImpl();
        RequestDTO<Animal> animalRequest = factory.createAnimal("特朗普");
        RequestDTO<People> peopleRequest = factory.createPeople("上帝");
        System.out.println("动物的名字是:"+animalRequest.getPayload().getName());
        System.out.println("人类的名字是:"+peopleRequest.getPayload().getName());
    }
}

参考资料:
https://blog.csdn.net/LoveLion/article/details/17517213#commentBox
《Java8 实战》

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章