Factory Method Pattern(工廠方法模式)與FactoryBean

參開資料:
Spring揭祕
設計模式之禪

先來看看Factory Method Pattern,我想搞一個工廠來生成一些bean

/*這是接口*/

public interface Person {

    public void say();
}
/*這是兩個實現類*/
public class WPerson implements Person {

    @Override
    public void say() {
        System.out.println("白種人");
    }
}
public class YPerson implements Person {

    @Override
    public void say() {
        System.out.println("黃種人");
    }
}

有了這兩個實現類,現在我想我給出一個Class,、就有一個工廠生產這個Class對應的一個實例給我。

FactoryBean代碼:

import com.factory.entity.Person;

public class MyFactoryBean {

    public static Person getInstance(Class s) {

        Person p = null;

        try {
             p = (Person)Class.forName(s.getName()).newInstance();

        } catch (InstantiationException e){

            System.out.println("沒找到這個類");

        } catch (IllegalAccessException e) {

            System.out.println("Person自身定義有問題");

        } catch (ClassNotFoundException e) {

            System.out.println("沒找到這個類");

        } 
        return p;
    }
}

然後這個FactoryBean就可以幹活了:

import com.factory.FactoryBean.MyFactoryBean;
import com.factory.entity.Person;
import com.factory.entity.WPerson;
import com.factory.entity.YPerson;

public class TestMain {

    public static void main(String ai[]) {

        Person p = MyFactoryBean.getInstance(WPerson.class);
        Person p1 = MyFactoryBean.getInstance(YPerson.class);
        p.say();
        p1.say();

    }
}

運行結果:
這裏寫圖片描述

Factory Method Pattern先說這些,
下面我們來看看Spring中用到這個模式的地方:
有時候,我們會用到第三方的類庫,需要實例化相關的類,這時,可以用Factory Method Pattern來避免藉口與實現類的耦合性。提供一個工廠類來實例化具體的藉口實現類,這樣主體對象只需要依賴工廠類,如果實現類有變更,主體對象就不需要做任何變動。
例如:

public class A {
    private Person p;
    public A() {
       //p = new WPerson();
       /*應避免這樣做,改用一下方式*/
       //p = MyFactoryBean.getInstance();
    }
}

當需求改變,不需要白人,而需要黃種人的時候,就可以只改MyFactoryBean的getInstance(),而不需要修改A類的原代碼。
,如果用上配置文件看上去就更方便了:

import com.factory.entity.Person;

public class TestService {

    private Person p;

    public Person getP() {
        return p;
    }

    public void setP(Person p) {
        this.p = p;
    }   
}

/*爲了方便,可以把MyFactotyBean的getInstance()方法稍作修改*/
public class MyFactoryBean {

    public static Person getInstance(String personName) {
    //把方法參數改成String類型的方便傳值。 
        Person p = null;

        try {
             p = (Person)Class.forName(personName).newInstance();

        } catch (InstantiationException e){

            System.out.println("沒找到這個類");

        } catch (IllegalAccessException e) {

            System.out.println("Person自身定義有問題");

        } catch (ClassNotFoundException e) {

            System.out.println("沒找到這個類");

        } 
        return p;
    }
}
    <!-- 配置Factory 
    指定factory-method之後,Factory就會返回該方法的返回值,而不是返回一個Factory的實例
    通過constructor-arg可以指定factory-method方法的參數,用法跟普通的用法一樣。如果沒有該方法沒有參數也可以不加,就直接使用factory-method就行了。
    -->
    <bean id="myFactory" class="com.factory.FactoryBean.MyFactoryBean" factory-method="getInstance" >
      <constructor-arg name="personName" value="com.factory.entity.WPerson" />
    </bean>

    <bean id="test" class="com.test.TestService">
      <property name="p">
        <ref bean="myFactory" />
        <!--此處得到的就不是myFactory的實例,而是factory-method返回的類型-->
      </property>
    </bean>

測試類:

public class TestMain {

    public static void main(String ai[]) {

        ApplicationContext ac = new ClassPathXmlApplicationContext("/applicationcontext.xml");
        TestService t = (TestService)ac.getBean("test");
        t.getP().say();
    }
}

測試結果:
這裏寫圖片描述
這是靜態工廠方法,使用的factory-method是一個靜態方法,
如果將getInstance()的static關鍵字去掉,程序會報錯:
這裏寫圖片描述

也可以使用非靜態的工廠方法,其他不變,只需要修改配置文件。

<!-- 配置Factory -->
    <!-- 先生成一個Factory,再使用 -->
    <bean id="myFactoryImp" class="com.factory.FactoryBean.MyFactoryBean" />

    <bean id="myFactory" factory-bean="myFactoryImp" factory-method="getInstance">
      <constructor-arg name="personName" value="com.factory.entity.WPerson" />
    </bean>

然後現在如果要修改成黃種人,就只需改很少的配置文件就行了。

現在我們再來看看 Spring中的FactoryBean

FactoryBean是Spring容器提供的一種可以擴展容器對象實例化邏輯的接口。更BeanFactory有着本質的區別,BeanFactory是Sopring的一種容器類型,還有一種是ApplicationContext。
這裏寫圖片描述

這是Spring中FactoryBean的源碼,

1.getObject()方法返回該FactoryBean生產的對象實例,
2.getObjectType()返回,getObject()方法生產出來的對象實例的類型。如果預選無法確定就返回null
3.isSingleton(),生成的對象實例是否要以singleton的形式存在於容器中,

提供這個接口當然就可以自己實現,

import org.springframework.beans.factory.FactoryBean;

import com.factory.entity.Person;

public class MyFactoryBean2 implements FactoryBean {

    private String personName;

    public String getPersonName() {
        return personName;
    }

    public void setPersonName(String personName) {
        this.personName = personName;
    }

    @Override
    public Object getObject() throws Exception {

        Person p = null;

        try {
             p = (Person)Class.forName(personName).newInstance();

        } catch (InstantiationException e){

            System.out.println("沒找到這個類");

        } catch (IllegalAccessException e) {

            System.out.println("Person自身定義有問題");

        } catch (ClassNotFoundException e) {

            System.out.println("沒找到這個類");

        } 
        return p;
    }

    @Override
    public Class getObjectType() {
        return Person.class;
    }

    @Override
    public boolean isSingleton() {
        /*設置true單例模式,設置false每次都生成一個*/
        return true;
    }
}

配置文件:

 <bean id="test" class="com.test.TestService" scope="prototype">
      <property name="p">
        <ref bean="myFactory" />
      </property>
    </bean>

    <bean id="myFactory" class="com.factory.FactoryBean.MyFactoryBean2">
      <property name="personName" value="com.factory.entity.YPerson" />
    </bean>

測試類:

public class TestMain {

    public static void main(String ai[]) {

        ApplicationContext ac = new ClassPathXmlApplicationContext("/applicationcontext.xml");
        TestService t = (TestService)ac.getBean("test");
        t.getP().say();
        TestService t1 = (TestService)ac.getBean("test");
        System.out.println(t + "\n" + t1);
        System.out.println(t.getP() + "\n" + t1.getP());
    }
}

運行結果:
這裏寫圖片描述

關於FactoryBean就說這麼多。

下面來看看
Factory Method Pattern(工廠方法模式)

繼續更新。。

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