【Spring源碼解析】FactoryBean-工廠方法模式的實現及使用

1、工廠方法模式中的三種模式的特色

工廠模式中的三種模式,分別是:簡單工廠模式、工廠方法模式、抽象工廠模式,三種分別是什麼,以及適合場景是什麼?spring

(1)簡單工廠模式:一個抽象接口對應一個產品接口,特定產品實現這個接口,針對不一樣產品均可以在同一個工廠中生產,同一個工廠生產產品能夠經過多種方式,單生產方法(經過類型斷定具體是要哪一個產品,並進行new返回),多生產方法(工廠中有多個產品的不一樣生產方法,每個生產方法對應一個new 產品的return),或者是靜態方法簡單工廠(將工廠中的返回某個產品的方法類設置爲static,則直接經過類調用靜態方法便可,不須要new工廠類的對象實例)緩存

該方法的問題是:若是要新增一個產品,必須對工廠類進行修改,可是若是經過反射或者其餘方式能夠作統一處理,其實也不會涉及到這個問題,若是要新增一個產品必需要對工廠類修改的時候,此時針對簡單工廠模式的修改以爲比較麻煩的話或者想要使擴展性更好的話,能夠經過工廠方法模式(備註:簡單工廠模式比較像一個集中廠,各類不一樣的東西都能產)ide

Client端去調用的時候,須要知道:工廠的類名,及提供的生產方法從而能夠得到具體產品的實例,以及產品的接口,能夠經過實例調用接口獲得須要的產品的信息this

其實就是:一個工廠類名Fatory,從工廠的生產方法獲取具體產品實例,getProduct()其中會返回new ProductA()或者new ProductB(),以後想要真正去進行產品的使用,還須要經過產品的接口,進行調用,例如ProductA.getProductInfo()等spa

(2)工廠方法模式:能夠看作是簡單工廠模式的升級版;工廠方法模式就是一個工廠接口和多個工廠實現類,要增長一個新的產品,增長一個新的工廠實現類便可,針對以前的老的工廠實現類也不須要修改.net

工廠方法模式至關於在簡單工廠模式的基礎上,增長了對於不一樣的產品進行多個不一樣工廠的實現類的添加,不一樣的工廠用於Get不一樣的產品,用於進行不一樣產品的具體生產代理

Client進行調用的時候,直接經過識別不一樣工廠,而後經過工廠接口類提供的公共方法,便可進行接口方法調用,獲取產品;還須要知道具體的產品接口,用於進行具體的產品信息的獲取code

(3)抽象工廠模式:針對有多個接口的狀況,應用於有多個產品族產生的狀況xml

抽象工廠模式中能夠定義不止一個接口,一個工廠也能夠生產不止一個產品類,可是即便是這樣,若是要新增一個新的接口,在其中須要修改的部分也是不少的,抽象工廠類的接口須要增長,其餘工廠對於該類型的產品的工廠實現要增長,同時能夠經過新建其餘產品類進行具體產品類的返回;可是若是針對某一個接口對應的產品門類的話,是能夠很方便的添加的,並且對老的工廠接口和具體的工廠類,都沒有影響,也就是說我想要建一個新的工廠,進行產品的生產,很容易。對象

2、Spring中的工廠方式模式的使用FactoryBean

FactoryBean是一個接口,具體包含的接口以下因此:

這三個接口具體含義是:

T getObject() throws Exception;    //返回此工廠管理的對象的實例
Class<?> getObjectType();    //返回此FactoryBean建立的對象的類型
//這個工廠返回的對象是不是單例,默認返回true;如果單例則由getObject返回的//是相同的對象,是能夠緩存的引用
default boolean isSingleton() {     
   return true;
}

基於此,咱們知道這個FactoryBean也用於生成對象實例,那麼其實也是一種Bean,該類型的Bean能夠做爲對經過xml或者普通的註解直接進行生成Bean的一種補充,簡單的說就是:能夠經過FactoryBean來返回你想要的Bean,該類的Bean的生成多是會比較複雜,或者你想要在作一些擴展操做的,均可以使用該方式

後面,能夠重點說明一下ProxyFactoryBean,這個部分會在代理模式的時候說明~

下面經過對FactoryBean的實現,看一下本身使用的效果,FactoryBean的代碼以下:

package factorybean.demo;

/**

 * Created by xiami on 2019/6/3.

 */

public interface FactoryBean <T> {

    T getObject();

    Class<?> getObjectType();

    default boolean isSingleton(){return true;}

}

下面是User類對FactoryBean的實現:

package factorybean.demo;

/**

 * Created by xiami on 2019/6/3.

 */

public class User implements FactoryBean {

    private String name;

    private String passWd;

    private int age;


    public void setAge(int age) {

        this.age = age;

    }

    public void setPassWd(String passWd) {

        this.passWd = passWd;

    }

    public void setName(String name) {

        this.name = name;

    }

    @Override

    public Object getObject() {

        if (age <= 0){

            return new Exception("年齡輸入錯誤");

        }

        else {

            return "輸入參數正確";

        }

    }

    @Override

    public Class<?> getObjectType() {

        return User.class;

    }

    public String getName() {

        return name;

    }

    public String getPassWd() {

        return passWd;
    }

    public int getAge() {

        return age;

    }

}

重點關注:在getObject()中針對輸入的不一樣age參數作了一個判斷,用於輸出參數是否異常

接下來是:

在springtest.xml文件中進行配置:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

       xmlns:context="http://www.springframework.org/schema/context"

       xsi:schemaLocation="http://www.springframework.org/schema/beans

       http://www.springframework.org/schema/beans/spring-beans.xsd

       http://www.springframework.org/schema/context

       http://www.springframework.org/schema/context/spring-context.xsd">

    <bean id="factorybeanUser" class="factorybean.demo.User">

        <property name="name" value="lxlx" />

        <property name="passWd" value="111" />

        <property name="age" value="1"/>

    </bean>

</beans>

注意,由於在簡單工廠模式中實現的GetBean還沒法解析FactoryBean的類型,所以這裏直接用的Spring-Framework做爲lib庫方便對Spring中的xml解析和GetBean的調用,Client調用類代碼以下:

package factorybean.demo;

import org.springframework.beans.BeansException;

import org.springframework.context.support.ClassPathXmlApplicationContext;

/**

 * Created by 58 on 2019/6/3.

 */
public class Client {
    public static void main(String[] args) throws BeansException {

        ClassPathXmlApplicationContext classPathXmlApplicationContext =
                new ClassPathXmlApplicationContext("classpath:factorybean/demo/springtest.xml");
        User user = (User)classPathXmlApplicationContext.getBean("factorybeanUser");
        System.out.println(user.getObject());
    }
}

當springtest.xml中配置age的值爲-1時,運行結果爲:

當springtest.xml中配置age的值爲12時,運行結果爲:

可見:經過對FactoryBean的接口的實現,在getObject()中可以返回本身想要的內容,經過GetBean()就能夠獲取到,以後的文章會對FactoryBean在GetBean中是何時被獲取作介紹

參考文章:

http://www.javashuo.com/article/p-tdvbctkv-kx.html

https://blog.csdn.net/zknxx/article/details/79588391

https://www.jianshu.com/p/6f0a59623090

相關文章
相關標籤/搜索