Spring 笔记四 :工厂模式与工厂方法、FactoryBean创建bean

本文详细介绍了三种工厂模式:简单工厂模式、工厂方法模式和抽象工厂模式。通过实例对比了各种模式的特点及适用场景,并探讨了如何在Spring框架中利用工厂方法和FactoryBean创建Bean。

#工厂模式

下面例子中鼠标,键盘,耳麦为产品,惠普,戴尔为工厂。

简单工厂模式(静态方法模式)

简单工厂模式不是 23 种里的一种,简而言之,就是有一个专门生产某个产品的类。

比如下图中的鼠标工厂,专业生产鼠标,给参数 0,生产戴尔鼠标,给参数 1,生产惠普鼠标。

组成(角色)关系作用
抽象产品(Product)具体产品的父类描述产品的公共接口
具体产品(Concrete Product)抽象产品的子类;工厂类创建的目标类描述生产的具体产品
工厂(Creator)被外界调用根据传入不同参数从而创建不同具体产品类的实例
抽象产品类 ``` public abstract class Mouse { public abstract void show(); } ``` 具体产品类: DellMouse
public class DellMouse extends Mouse{
    public void show(){
        System.out.println("hello,I 'm dell mouse");
    }
}

HpMouse

public class HpMouse extends Mouse{
    public void show(){
        System.out.println("hello,I 'm hp mouse");
    }
}

工厂类:

public class MouseFactory {
    public static Mouse manufacture(int choose){
        switch (choose){
            case 0:
                return new DellMouse();
            case 1:
                return new HpMouse();
            default:
                return null;
        }
    }
}

Main:

public class Main {
    public static void main(String[] args) {
        Mouse m = MouseFactory.manufacture(1);
        m.show();
    }
}

缺点:
1.违背“开放 - 关闭原则”,一旦添加新产品就不得不修改工厂类的逻辑,这样就会造成工厂逻辑过于复杂。
2.工厂类集中了所有实例(产品)的创建逻辑,一旦这个工厂不能正常工作,整个系统都会受到影响。

工厂模式(工厂方法模式)

工厂模式也就是鼠标工厂是个父类(抽象类)

戴尔鼠标工厂,惠普鼠标工厂继承它,可以分别生产戴尔鼠标,惠普鼠标。

生产哪种鼠标不再由参数决定,而是创建鼠标工厂时,由戴尔鼠标工厂创建。

后续直接调用鼠标工厂.生产鼠标()即可

工厂方法模式把具体产品的创建推迟到工厂类的子类(具体工厂)中,此时工厂类不再负责所有产品的创建,符合开放封闭原则,克服了简单工厂模式中缺点.

MouseFactory类:

abstract class MouseFactory {
    public abstract  Mouse manufacture();
}

DellMouseFactory

public class DellMouseFactory extends MouseFactory {
    @Override
    public Mouse manufacture() {
        return new DellMouse();
    }
}

HpMouseFactory

public class HpMouseFactory extends MouseFactory {
    @Override
    public Mouse manufacture() {
        return new HpMouse();
    }
}

Main

public class Main {
    public static void main(String[] args) {
        DellMouseFactory df= new DellMouseFactory();
        df.manufacture().show();
    }
}

抽象工厂模式

工厂方法模式存在一个严重的问题: **一个具体工厂只能创建一类产品** 而在实际过程中,一个工厂往往需要生产多类产品。为了解决上述的问题,我们又使用了一种新的设计模式:抽象工厂模式。

抽象工厂模式也就是不仅生产鼠标,同时生产键盘。

也就是 PC 厂商是个父类,有生产鼠标,生产键盘两个接口。

戴尔工厂,惠普工厂继承它,可以分别生产戴尔鼠标+戴尔键盘,和惠普鼠标+惠普键盘。

创建工厂时,由戴尔工厂创建。

后续工厂.生产鼠标()则生产戴尔鼠标,工厂.生产键盘()则生产戴尔键盘。

步骤1: 创建抽象工厂Factory 类,定义具体工厂的公共接口

public abstract class Factory {
    public abstract Mouse manufactureMouse();
    public abstract KeyBoard manufactureKeyBoard();
}

步骤2: 创建抽象产品族Product类 ,定义具体产品的公共接口;

public abstract class Product {
    public abstract void show();
}

创建抽象产品类Mouse,KeyBoard ,定义具体产品的公共接口
Mouse

public abstract class Mouse extends Product{
    public abstract void show();
}

KeyBoard

public abstract class KeyBoard extends Product {
    @Override
    public abstract void show();
}

创建具体产品类(继承抽象产品类)HpMouse,DellMouse,HpKeyboard,DellKeyboard, 定义生产的具体产品;
HpMouse

public class HpMouse extends Mouse {
    public void show(){
        System.out.println("hello,I 'm hp mouse");
    }
}

DellMouse

public class DellMouse extends Mouse {
    public void show(){
        System.out.println("hello,I 'm dell mouse");
    }
}

HpKeyboard

public class HpKeyBoard extends KeyBoard {
    @Override
    public void show() {
        System.out.println("pili pala...I'm HpKeyBoard!");
    }
}

DellKeyboard

public class DellKeyBoard extends KeyBoard {
    @Override
    public void show() {
        System.out.println("pilipala...I'm DellKeyboard!");
    }
}

步骤5:创建具体工厂类(继承抽象工厂类),定义创建对应具体产品实例的方法;
DellFactory

public class DellFactory extends Factory{
    @Override
    public Mouse manufactureMouse() {
        return new DellMouse();
    }

    @Override
    public KeyBoard manufactureKeyBoard() {
        return new DellKeyBoard();
    }
}

HpFactory

public class HpFactory extends Factory {
    @Override
    public Mouse manufactureMouse() {
        return new HpMouse();
    }

    @Override
    public KeyBoard manufactureKeyBoard() {
        return new HpKeyBoard();
    }
}

步骤6:客户端通过实例化具体的工厂类,并调用其创建不同目标产品的方法创建不同具体产品类的实例

public class Main {
    public static void main(String[] args) {
       DellFactory df = new DellFactory();
       HpFactory hf = new HpFactory();
       df.manufactureKeyBoard().show();
       df.manufactureMouse().show();
       hf.manufactureKeyBoard().show();
       hf.manufactureMouse().show();
    }
}

在抽象工厂模式中,假设我们需要增加一个工厂

假设我们增加华硕工厂,则我们需要增加华硕工厂,和戴尔工厂一样,继承 PC 厂商。

之后创建华硕鼠标,继承鼠标类。创建华硕键盘,继承键盘类即可。

在抽象工厂模式中,假设我们需要增加一个产品

假设我们增加耳麦这个产品,则首先我们需要增加耳麦这个父类,再加上戴尔耳麦,惠普耳麦这两个子类。

之后在PC厂商这个父类中,增加生产耳麦的接口。最后在戴尔工厂,惠普工厂这两个类中,分别实现生产戴尔耳麦,惠普耳麦的功能。 以上。

参考文章:
抽象工厂模式(Abstract Factory)- 最易懂的设计模式解析
菜鸟教程 抽象工厂模式
#工厂方法创建bean
我们再回顾一下配置Bean

  • 配置形式:基于XML文件的方式;基于注解的方式;
  • Bean配置方式:通过全类名反射,通过工厂方法(静态工厂方法&实例工厂方法),FactoryBean

有些时候(貌似很少),项目中需要通过工厂方法来创建 Bean 实例。这里的工厂可分为静态工厂和实例工厂。


/**
 * 静态工厂方法:直接调用某个类的静态方法,就可以得到一个对象(代替new)
 * Created by kaixin on 2018/8/22.
 */
public class StaticCarFactory {
    //静态工厂方法
    public static Car getCar(String name){
        return cars.get(name);
    }

    private  static Map<String,Car> cars = new HashMap<>() ;

    static {
        cars.put("changan",new Car("changan",23000));
        cars.put("changhe",new Car("changhe",12000));
    }
}

/**
 *  实例工厂方法: 实例工厂的方法,即先创建工厂本身,再调用实例方法返回bean。
 *  Created by kaixin on 2018/8/22.
 */
public class InstanceCarFactory {
    private Map<String,Car> cars =null;

    public InstanceCarFactory() {
        cars= new HashMap<>();
        cars.put("benteng",new Car("benteng",12000));
    }
    public  Car getCar(String name){
        return cars.get(name);
    }
}

public class Main {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext actxt = new ClassPathXmlApplicationContext("beans-factory.xml");
        Car carone =(Car) actxt.getBean("carone");
        Car cartwo =(Car) actxt.getBean("cartwo");
        System.out.println(carone);
        System.out.println(cartwo);
        actxt.close();
    }
}

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--通过静态工厂方法配置bean -->
    <!--class属性指向静态工厂的全类名
        factory-method:  指向静态工厂方法的名字
        constructor-arg:如果工厂方法需要传入参数,则使用该属性传入-->
    <bean id="carone" class="com.spring.factory.StaticCarFactory" factory-method="getCar">
        <constructor-arg value="changhe"></constructor-arg>
    </bean>

    <!--配置工厂的实例 -->
    <bean id="carFactory" class="com.spring.factory.InstanceCarFactory" ></bean>

    <!--
    通过实例工厂方法来配置bean
    factory-bean指向实例工厂方法的bean
     -->
    <bean id="cartwo" factory-bean="carFactory" factory-method="getCar">
        <constructor-arg value="benteng"></constructor-arg>
    </bean>
</beans>

#FactoryBean创建Bean
###应用场景
FactoryBean 通常是用来创建比较复杂的bean,一般的bean 直接用xml配置即可,但如果一个bean的创建过程中涉及到很多其他的bean 和复杂的逻辑,用xml配置比较困难,这时可以考虑用FactoryBean。

实现方法

自己写个MyFactoryBean 实现FactoryBean接口

public class CarFactoryBean implements FactoryBean {
    private String brand;

    public void setBrand(String brand) {
        this.brand = brand;
    }

    @Override
    public Car getObject() throws Exception {
        return new Car(brand,5000000);
    }

    /**
     * 返回bean的类型
     */
    @Override
    public Class<?> getObjectType() {
        return Car.class;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }
}

xml文件中的配置

	<!--
		通过 FactoryBean配置bean实例
		class: 指向FactoryBean的全类名
		property: 指向FactoryBean的属性
		但实际返回的是FactoryBean的getObject() bean对象
	-->
    <bean id="car" class="com.spring.factorybean.CarFactoryBean">
    <property name="brand" value="BMW"></property>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值