工厂模式在源码中的应用和工厂模式的总结

工厂模式在Spring框架和JDK源码中的应用

这一节我们看看工厂模式在Spring框架和JDK源码中的应用:

一、Spring中的工厂模式

1.1 简单工厂BeanFactory

Spring中的BeanFactory就是简单工厂模式的体现,根据传入一个唯一的标识来获得Bean对象

图片

我们可以看到DefaultListableBeanFactory实现了这个工厂方法:

图片

我们看一下接口BeanFactory:

图片

DefaultListableBeanFactory和BeanFactory的关系:

图片

1.2 工厂方法FactoryBean

实现原理:

实现了FactoryBean接口的bean是一类叫做factory的bean。其特点是Spring会在使用getBean()调用获得该bean时,会自动调用该bean的getObject()方法,所以返回的不是factory这个bean,而是这个bean.getOjbect()方法的返回值。

图片

AbstractFactoryBean:

图片

我们看下FactoryBean的一个小栗子可能会比较有感觉:

图片

使用XML的注入方式:

图片

具体的测试代码:

图片

二、JDK中的工厂模式

在JDK源码中 ,java.util.Calendar使用了工厂模式的简单工厂模式。

找到getInstance()方法,跟进去可以看到如下的代码:

图片

工厂模式实战之不同的支付渠道

图片

在实际项目中,我们会引入支付宝支付和微信支付,如果是按照常规的设计我们会这么设计:

图片

设计两个支付类AliPay和WeixinPay,然后在调用的时候,实例化相应的类来进行发起支付,这种方式对于调用者而言,不是很友好,扩展性不强。那么我们就可以使用简单工厂模式或者工厂方法模式进行优化。

这里我们使用简单工厂模式优化一下,工厂方法模式思路和我们上面讲的BMW是一样的。

一、工厂模式实战之不同的支付渠道

1.1 类图

只要了解了简单工厂模式,具体的编码还是很简单的,我们来看下类图:

图片

1.2 编码

有了类图,编码就很简单了。

1.2.1 抽象产品角色

在接口PayChannel定义了pay()的方法:

package com.kfit.factory.example.v2;

import java.math.BigDecimal;

/\*\*
 \* 支付渠道接口
 \*
 \* @author 悟纤「公众号SpringBoot」
 \* @date 2020-11-20
 \* @slogan 大道至简 悟在天成
 \*/
public interface PayChannel {
    /\*\*
     \* 定义支付方法
     \* @param price 支付的价格
     \* @return 调用是否成功,true:成功,false:失败.
     \*/
    boolean pay(BigDecimal price);
}


复制代码

1.2.2****具体产品角色

这里主要有AliPay和WeixinPay:

AliPay:

package com.kfit.factory.example.v2;

import java.math.BigDecimal;

/\*\*
 \*
 \* 支付宝支付调用
 \*
 \* @author 悟纤「公众号SpringBoot」
 \* @date 2020-11-20
 \* @slogan 大道至简 悟在天成
 \*/
public class AliPay implements PayChannel{

    @Override
    public boolean pay(BigDecimal price){
        System.out.println("调用支付宝SDK发起支付,价格:"+price);
        return true;
    }

}

复制代码

WeixinPay:

package com.kfit.factory.example.v2;

import java.math.BigDecimal;

/\*\*
 \*
 \* 微信支付调用
 \*
 \* @author 悟纤「公众号SpringBoot」
 \* @date 2020-11-20
 \* @slogan 大道至简 悟在天成
 \*/
public class WeixinPay implements PayChannel{

    @Override
    public boolean pay(BigDecimal price){
        System.out.println("调用微信支付SDK发起支付,价格:"+price);
        return true;
    }

}


复制代码

1.2.3****具体工厂角色

具体工厂角色PayChannelFactory:

package com.kfit.factory.example.v2;

/\*\*
 \* 支付方式工厂类
 \*
 \* @author 悟纤「公众号SpringBoot」
 \* @date 2020-11-20
 \* @slogan 大道至简 悟在天成
 \*/
public class PayChannelFactory {

    /\*\*
     \* 这个type一般是前端会使用单选按钮进行让用户选择,我们就可以在单选按钮上进行设置对应的值为0或者1
     \* @param type 0:支付宝,1:微信支付.
     \* @return
     \*/
    public static PayChannel getPayChannel(int type){
        PayChannel payChannel = null;
        if(type == 0){
            payChannel = new AliPay();
            //在这里设置发起支付需要的一些配置信息,比如appId,加密方式等
        }else if(type == 1){
            payChannel = new WeixinPay();
            //在这里设置发起支付需要的一些配置信息,比如appId,加密方式等
        }else{
            throw new RuntimeException("不支持支付方式,type取值\[0|1\],0:支付宝,1:微信支付");
        }

        return payChannel;
    }
}

复制代码

1.3 测试

package com.kfit.factory.example.v2;

import java.math.BigDecimal;

/\*\*
 \* 测试支付
 \*
 \* @author 悟纤「公众号SpringBoot」
 \* @date 2020-11-20
 \* @slogan 大道至简 悟在天成
 \*/
public class Test {
    /\*\*
     \* 这种方式对于使用者而言,不是很优化,所以我们进行优化。
     \* 
     \* @param args
     \*/
    public static void main(String\[\] args) {
        //使用支付宝支付
        PayChannel payChannel = PayChannelFactory.getPayChannel(0);
        payChannel.pay(new BigDecimal(88.88));

        //使用微信支付
        payChannel = PayChannelFactory.getPayChannel(1);
        payChannel.pay(new BigDecimal(88.88));
    }
}


复制代码

工厂模式总结

这一节我们轻松一下,我们对于前面的简单工厂、工厂方法、抽象工厂做个总结。

一、工厂模式

1.1 定义

简单工厂(Simple Factory):由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类(继承自一个父类或接口)的实例。

工厂方法(Factory Method):定义工厂父类指定公共的接口,而子类工厂则负责生成具体的对象(多个工厂)。

抽象工厂(Abstract Factory):提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类;具体的工厂负责实现具体的产品实例(工厂中可以生产多个产品)。

1.2 主要对象

简单工厂:具体工厂(一个)、抽象产品、具体产品

工厂方法:抽象工厂、具体工厂(多个)、抽象产品、具体产品

抽象工厂:抽象工厂、具体工厂(多个)、抽象产品(族)、具体产品

抽象工厂的多个有两层含义:多个工厂的实现,每个实现有多个创建产品的方法。

简单工厂模式主要对象:

简单工厂模式又叫做静态工厂方法模式,不属于23种GOF设计模式之一。将简单工厂模式(Simple Factory)看为工厂方法模式的一种特例,两者归为一类。

工厂(Factory):负责实现创建所有实例的内部逻辑,并提供一个外界调用的方法,创建所需的产品对象。

抽象产品(Product):负责描述产品的公共接口

具体产品(ConcreteProduct):描述生产的具体产品。

工厂方法模式主要对象:

抽象工厂(Abstract Factory):描述具体工厂的公共接口

具体工厂(ConcreteFactory):描述具体工厂,创建产品的实例,供外界调用

抽象产品(Product):负责描述产品的公共接口

具体产品(ConcreteProduct):描述生产的具体产品

抽象工厂模式主要对象:

抽象工厂(AbstractFactory):描述具体工厂的公共接口,一般可以生成两个产品

具体工厂(ConcreteFactory):描述具体工厂,创建产品的实例,供外界调用

抽象产品(族)(AbstractProduct):描述抽象产品的公共接口

具体产品(ConcreteProduct):描述具体产品的公共接口

1.3 区别

工厂方法模式:

一个抽象产品类,可以派生出多个具体产品类。

一个抽象工厂类,可以派生出多个具体工厂类。

每个具体工厂类只能创建一个具体产品类的实例。

抽象工厂模式:

多个抽象产品类,每个抽象产品类可以派生出多个具体产品类。

一个抽象工厂类,可以派生出多个具体工厂类。

每个具体工厂类可以创建多个具体产品类的实例。

区别:

工厂方法模式只有一个抽象产品类,而抽象工厂模式有多个。

工厂方法模式的具体工厂类只能创建一个具体产品类的实例,而抽象工厂模式可以创建多个。

1.4 适用场景

简单工厂模式:

工厂类中创建的对象不能太多,否则工厂类的业务逻辑就太复杂了,其次由于工厂类封装了对象的创建过程,所以客户端应该不关心对象的创建。适用场景:

(1)需要创建的对象较少。

(2)客户端不关心对象的创建过程。

工厂方法模式:

和简单工厂对比一下,最根本的区别在于,简单工厂只有一个统一的工厂类,而工厂方法是针对每个要创建的对象都会提供一个工厂类。适用场景:

(1)客户只知道创建产品的工厂名,而不知道具体的产品名。如 TCL 电视工厂、海信电视工厂等。

(2)创建对象的任务由多个具体子工厂中的某一个完成,而抽象工厂只提供创建产品的接口。

(3)客户不关心创建产品的细节,只关心产品的品牌

抽象工厂模式:

抽象工厂的适用场景:

(1)和工厂方法一样客户端不需要知道它所创建的对象的类。

(2)需要一组对象共同完成某种功能时。并且可能存在多组对象完成不同功能的情况。

(3)系统结构稳定,不会频繁的增加对象。(因为一旦增加就需要修改原有代码,不符合开闭原则)。

二、小结

无论是简单工厂模式,工厂方法模式,还是抽象工厂模式,他们都属于工厂模式,在形式和特点上也是极为相似的,他们的最终目的都是为了解耦。

在使用时,我们不必去在意这个模式到底工厂方法模式还是抽象工厂模式,因为他们之间的演变常常是令人琢磨不透的。

经常你会发现,明明使用的工厂方法模式,当新需求来临,稍加修改,加入了一个新方法后,由于类中的产品构成了不同等级结构中的产品族,它就变成抽象工厂模式了;而对于抽象工厂模式,当减少一个方法使的提供的产品不再构成产品族之后,它就演变成了工厂方法模式。

所以,在使用工厂模式时,只需要关心降低耦合度的目的是否达到了。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享