參開資料:
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(工廠方法模式)
繼續更新。。