设计模式——工厂方法模式 和 抽象工厂模式

工厂方法

定义:定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。

通用类图:

在网上购物的都知道在线支付功能,支付方式有很多种,如:支付宝、微信、银行卡等等。支付方式的选择就比较符合工厂方式,比如: 

AbstractPayFactory:类图里的Creator

PayFactory:类图里的ConcreteFactory

PayChannel:类图里的产品类Product

AliPay或WeiXinPay:类图里的ConcreteProduct

AbstractPayFactory 工厂类实现:

public abstract class AbstractPayFactory {
    /**
     * 传入Enum、Class或String等告诉具体工厂需要返回一个什么支付渠道
     * @param c
     * @param <T>
     */
    public abstract <T extends PayChannel>  PayChannel createPayChannel(Class<T> c);
}

PayFactory 实现:

public class PayFactory extends AbstractPayFactory {
    @Override
    public <T extends PayChannel> PayChannel createPayChannel(Class<T> c) {
        PayChannel channel = null;

        try {
            channel = (PayChannel) Class.forName(c.getName()).newInstance();
        } catch (Exception e) {
            //TODO:
        }
        return (T) channel;
    }
}
    //标准工厂使用
    @Test
    public void testFactory(){
        AbstractPayFactory factory = new PayFactory();
        PayChannel payChannel = factory.createPayChannel(AliPay.class);
        payChannel.pay();
    }

1、简单工厂 

一个工厂就可以满足创建不同支付渠道,而且可以使用静态方法,这样就没必要创建支付工厂实例了。

在工厂方法上去掉AbstractPayFactory抽象类,并把createPayChannel改为静态方法,如下所示:

public class SimpleFactory {
    public static  <T extends PayChannel> PayChannel createPayChannel(Class<T> c) {
        PayChannel channel = null;

        try {
            channel = (PayChannel) Class.forName(c.getName()).newInstance();
        } catch (Exception e) {
            //TODO:
        }
        return (T) channel;
    }
}

使用方式:

//简单工厂使用
    @Test
    public void testSimpleFactory(){
        PayChannel payChannel = SimpleFactory.createPayChannel(AliPay.class);
        payChannel.pay();
    }

2、多个工厂类 

随着平台快速壮大,用户量的增多,为了方便用户付款,支持的在线支付方式越来越多。不同支付方式需要在创建后做不同的初始化操作,客户端使用起来就比较麻烦了,而且也不应该由客户端来初始化。但是如果由工厂方法创建对象后再去初始化,又比较复杂,而且以后每增加一种支付方式,都得修改初始化方式。如果把创建支付方式+初始化放到单独的一个工厂方法里去实现,一种工厂方法只关注一个支付方式(创建并初始化),返回给客户端一个拿来即用的对象,以后每次增加支付方式,只需要扩展对应的工厂出来就可以了,这就是工厂方法扩展的多个工厂类形式,类图如下:

按照类图构建的支付方式关系图:

具体工厂示例:

public class AliPayFactory extends AbstractPayFactory {
    @Override
    public PayChannel createPayChannel() {
        AliPay pay = new AliPay();
        /**做一些不同的初始化*/
        pay.desc();
        return pay;
    }
}

不需要再根据传入参数来决定创建什么对象,工厂方法职责单一,一个工厂创建一个支付渠道(产品)

    //多工厂使用
    @Test
    public void testMutilFactory(){
        PayChannel aliPay = (new AliPayFactory()).createPayChannel();
        aliPay.pay();

        PayChannel weiXinPay = (new WeiXinPayFactory()).createPayChannel();
        weiXinPay.pay();
    }

用支付宝扫码支付……
用支付宝支付……
用微信扫码支付……
用微信支付……

抽象工厂

定义:为创建一组相关或相互依赖的对象提供一个接口,而且无需指定它们的具体类。

类图:

从源码类图来看:其实抽象工厂是工厂方法(多个工厂类)的升级版本,将一个产品升级为了多个产品,多个工厂负责创建不同的一类相关或相互依赖的产品。

支付工具为了推广自己往往在支付成功后有个抽奖功能,比如返回积分或现金等方式,将【支付】 和 【积分】类比两个产品,现以支付宝微信支付为例,如下图所示:

 

微信支付工厂只关注微信的支付方式和微信自己的积分或返现实现;支付宝也同样只关注自己的。

    @Test
    public void testAbstractFactory(){
        AbstractFactory aliPayFactory = new AliPayFactory();
        IPay alipay = aliPayFactory.createPay();
        IScore aliscore = aliPayFactory.createScore();
        alipay.pay();
        aliscore.getScore();

        AbstractFactory weiXinPayFactory = new WeiXinPayFactory();
        IPay wxpay = weiXinPayFactory.createPay();
        IScore wxscore = weiXinPayFactory.createScore();
        wxpay.pay();
        wxscore.getScore();
    }

支付宝发起支付申请……
支付宝通过face验证……
支付宝支付成功……
支付宝支付成功,获取4元返现,并获取1个蚂蚁积分


微信发起支付申请……
微信通过指纹验证……
微信支付成功……
微信支付成功,获取9元返现

使用的时候只用创建相关的工厂即可从工厂获取一系列的产品的创建方法。 

简化客户端调用,可以加个PayFactory,封装产品族的调用(模板方法)

PayFactory实现:

public class PayFactory {
    private IPay pay;
    private IScore score;

    public PayFactory(AbstractFactory factory) {
        this.pay = factory.createPay();
        this.score = factory.createScore();
    }

    public void pay() {
        this.pay.pay();
        this.score.getScore();
    }
}

客户端使用: 

    @Test
    public void testPayFactory(){
        AbstractFactory aliPayFactory = new factorymethod.abstractfactory.AliPayFactory();
        factorymethod.abstractfactory.PayFactory factory = new factorymethod.abstractfactory.PayFactory(aliPayFactory);
        factory.pay();
    }

客户端传入对应的工厂就行,封装具体产品的实现过程,对外隐藏细节。类图如下:

这就是抽象工厂模式,与工厂方法多个工厂类区别就是:工厂方法关注的是单个产品;抽象工厂关注的是一系列相关或相互依赖的产品的切换。

代码示例

原文地址:https://www.cnblogs.com/mr-yang-localhost/p/9652130.html