Spring中常见的设计模式—工厂模式

前言

今天来和小伙伴们分享下设计模式中的工厂模式

顺便带来了下面三个问题,一起来看看吧

![]( https://s4.51cto.com/images/blog/202108/05/ab852bfafa04224ff5d103f6f76d0007.png?x-oss-process=image/watermark ,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=)

一、工厂模式

我们都知道,设计模式有23种,按照功能和使用场景可以分为三大类:

  • 创建型模式
  • 结构型模式
  • 行为型模式

工厂设计模式(Factory Pattern)呢,就是一种很常见的设计模式,属于创建型模式的,主要作用就是来创建对象的~

原理图

![]( https://s4.51cto.com/images/blog/202108/05/e9a622b02f49cfcad53fe1536030da41.png?x-oss-process=image/watermark ,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=)

先来看一个小栗子

二、简单工厂模式(非23种)

原理图

![]( https://s4.51cto.com/images/blog/202108/05/31a76e12c92b660ca70051f249375749.png?x-oss-process=image/watermark ,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=)

例子的话,感觉也挺多的 比如各种品牌的电脑呀,手机呀,家具呀……

比如笔记本电脑的例子

抽取公共接口

这里就只提供一个返回品牌的接口

public interface ILaptop {
    String brand();
}1.2.3.

接口实现类

这里就举两个例子~

public class HuaWeiLaptop implements ILaptop{
    @Override
    public String brand() {
        return "HuaWei";
    }
}
​
public class MacLaptop implements ILaptop {
    @Override
    public String brand() {
        return "Mac";
    }
}1.2.3.4.5.6.7.8.9.10.11.12.13.

工厂类

最主要的就是这个工厂类了,我们把创建对象的能力将给它~

public class LaptopFactory {
​
    public static ILaptop createLaptop(String brand){
        switch (brand){
            case "HuaWei":
                return new HuaWeiLaptop();
            case "Mac":
                return new MacLaptop();
            default:
                return null;
        }
    }
}1.2.3.4.5.6.7.8.9.10.11.12.13.

测试

就这样,我们就简单的完成了一个工厂模式的应用了~ ,以后创建对象就直接调用工厂的方法就可以了

public class LaptopMain {
    public static void main(String[] args) {
        ILaptop hw = LaptopFactory.createLaptop("HuaWei");
        String brand = hw.brand();
        System.out.println(brand);
    }
}1.2.3.4.5.6.7.

当然,这个是最简单的工厂模式例子了,也叫做 简单工厂模式

当然这个也有很明显的弊端,所以我们再来看看这个 工厂方法模式

三、工厂方法模式

原理图

![]( https://s4.51cto.com/images/blog/202108/05/fdbd5c3c2227e263b1e93acbcb59113f.png?x-oss-process=image/watermark ,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=)

想想简单工厂的写法,将创建对象的所有操作都封装在一个工厂里,是不合理的,所以我们要进一步解耦

抽取工厂公共接口

public interface ILaptopFactory {
    ILaptop createLaptop();
}1.2.3.

工厂实现类

public class HuaweiLaptopFactory implements ILaptopFactory{
    @Override
    public ILaptop createLaptop() {
        return new HuaWeiLaptop();
    }
}1.2.3.4.5.6.

测试

简单改动上面测试案例的前两句代码即可

 HuaweiLaptopFactory huaweiLaptopFactory = new HuaweiLaptopFactory();
 ILaptop mac =  huaweiLaptopFactory.createLaptop();1.2.

是不是很简单的就完成了这个工厂模式了

四、抽象工厂模式

原理图

![]( https://s4.51cto.com/images/blog/202108/05/dfa2f69c8759f597ad2498c939a51136.png?x-oss-process=image/watermark ,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=)

那么工厂嘛,肯定不止一条生产线,它肯定有其他的业务,比如手机呀,其他电器啥的。

所以我们再重复上面笔记本产品的例子,再建一些其他类,然后也通过工厂类去创建它即可。

抽象工厂

先定义一个抽象工厂

public abstract class AbstractFactory {
    public abstract IPhone createPhone();
    public abstract ILaptop createLaptop();
}1.2.3.4.

工厂实现类

也就多了一个而已呀~

public class HuaweiFactory extends AbstractFactory{
    @Override
    public IPhone createPhone() {
        return new HuaWeiPhone();
    }
​
    @Override
    public ILaptop createLaptop() {
        return new HuaWeiLaptop();
    }
}1.2.3.4.5.6.7.8.9.10.11.

五、小结

在使用工厂模式时,我们可以发现从 简单工厂(非23种) ——》 工厂方法 ——》抽象工厂

这是一个不断扩展,解耦的过程,我们可以在项目种根据需要进行选择~

比如 产品多的话就选抽象工厂,单一的话就直接用工厂或者简单工厂就可以了

至此,我们了解到工厂模式是属于23中设计模式中的创建型模式,主要用途就是创建对象,同时方便程序解耦。

接着,我们再来想想 Spring 中和工厂模式有关的

![]( https://s4.51cto.com/images/blog/202108/05/c565b6ef4b3c59b66d0f784baa3ce667.png?x-oss-process=image/watermark ,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=)

说到这里,你想到什么了呢?

不知道的话,就默念 Factory,Factory,Factory …… 哈哈哈

是不是脑海中一下子浮现出来了这两货

  • BeanFactory
  • FactoryBean

从名字就可以看出这两货和工厂有关 (分别通过 getBeangetObject 获取对象)

那么我们先来介绍下他们叭

六、BeanFactory

源码的第一句话

The root interface for accessing a Spring bean container. (IOC的根接口)

可以发现它是非常核心的组件

遵循严格的生命周期

![]( https://s4.51cto.com/images/blog/202108/05/806b147c94c2ea5998b6cf643e5be59a.png?x-oss-process=image/watermark ,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=)

可以发现,通过 BeanFactory 创建一个 Bean 要经过非常严格的流程处理,很繁琐。

方法

![]( https://s4.51cto.com/images/blog/202108/05/98321e906e992b9598a0ddb6fa96a3b3.png?x-oss-process=image/watermark ,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=)

方法有很多,比如 获取别名呀,类型呀,是否是单例,原型等

通过 getBean 去获取对象

主要作用

根据 BeanDefinition 生成相应的 Bean 对象。

![]( https://s4.51cto.com/images/blog/202108/05/802be8f14b158ec1b54e55c0dbcd20d6.png?x-oss-process=image/watermark ,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=)

七、FactoryBean

源码

可以发现就这么三个方法,一个小工厂

![]( https://s4.51cto.com/images/blog/202108/05/5a00b220c59968f102d4053c54b46b66.png?x-oss-process=image/watermark ,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=)

通过 getObject 方法来返回一个对象

获取对象时:

  • 如果 beanName 没有加 & 号,则获取的是泛型T 的对象。
  • 如果添加了 & 号,获取的是实现了 FactoryBean 接口本身的对象,如 EhCacheFactoryBean

而正因为它的小巧,它也被广泛的应用在Spring内部,以及Spring与第三方框架或组件的整合过程中。

八、BeanFactory 和 FactoryBean 的区别是什么?

  • BeanFactory 是一个大工厂,是IOC容器的根基,有繁琐的 bean 生命周期处理过程,可以生成出各种各样的 Bean
  • FactoryBean 是一个小工厂,它自己也是一个 Bean ,但是可以生成其他 Bean

![]( https://s4.51cto.com/images/blog/202108/05/69987dba0616479b81037d3b7ebfb60a.png?x-oss-process=image/watermark ,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=)

最后一个问题

九、Spring中工厂模式的使用

既然都和工厂有关,那么我们就挑个软柿子捏一下

FactoryBean工厂模式图

![]( https://s4.51cto.com/images/blog/202108/05/1d67aa9e7e410f9f448ee25c0c32f9b3.png?x-oss-process=image/watermark ,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=)

可以发现和我们上面介绍的工厂方法模式一样,公共接口和不同的实现类,通过具体的工厂获取对象。

BeanFactory 也是类似的,就不画啦

十、总结

画个图总结下啦

![]( https://s4.51cto.com/images/blog/202108/05/4ea1725d4bcb4e151e4c2a833a3a892b.png?x-oss-process=image/watermark ,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=)

posted @ 2021-08-22 16:41  Java小叮当  阅读(1661)  评论(0)    收藏  举报