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(工厂方法模式)

继续更新。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值