Spring 工厂方法
IOC 是典型的工厂模式,现在来学习如何使用工厂模式来创建 bean。
说明:在学习这一部分内容之前,请读者自行复习或者补充设计模式中工厂模式的这一部分背景知识,要知道创建一个对象时,采用工厂模式不是多此一举,而是对象的初始化非常有必要的操作。如果对这个不了解,那么阅读本文时,会觉得这种既操作多余,也不甚理解。
漫画:设计模式之“工厂模式”
IoC 通过模式创建 bean 有两种方式:
- 静态工厂方法
- 实例工厂方法
1. 静态工厂方法
第一步:创建 Car 实体类;
package com.trainingl.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Car {
private int num;
private String brand;
}
第二步:创建静态工厂类,静态工厂方法;
package com.trainingl.Factory;
import com.trainingl.entity.Car;
import java.util.HashMap;
import java.util.Map;
public class StaticCarFactory {
private static Map<Integer,Car> cars;
static {
cars = new HashMap<Integer, Car>();
cars.put(1,new Car(1,"奥迪"));
cars.put(2,new Car(2,"奥拓"));
cars.put(3,new Car(3,"奔驰"));
cars.put(4,new Car(4,"宝马"));
}
public static Car getCar(int num){
return cars.get(num);
}
}
第三步:在 spring.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"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd
">
<!--配置静态工厂创建Car对象-->
<bean id="car1" class="com.trainingl.Factory.StaticCarFactory" factory-method="getCar">
<constructor-arg value="1"></constructor-arg>
</bean>
</beans>
factory-method
指向类的静态方法;constructor-arg
的 value 属性为调用静态方法所传的参数;
第四步:在测试类中直接获取 car1 对象;
package com.trainingl.test;
import com.trainingl.entity.Car;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test2 {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
Car car = (Car)applicationContext.getBean("car1");
System.out.println(car);
}
}
2. 实例工厂方法
第一步:创建实例工厂类,工厂方法;
package com.trainingl.Factory;
import com.trainingl.entity.Car;
import java.util.HashMap;
import java.util.Map;
public class InstanceCarFactory {
private Map<Integer, Car> carMap;
public InstanceCarFactory(){
carMap = new HashMap<Integer, Car>();
carMap.put(1,new Car(1,"本田"));
carMap.put(2,new Car(2,"奥迪"));
carMap.put(3,new Car(3,"宝马"));
}
public Car getCar(Integer num){
return carMap.get(num);
}
}
第二步:spring.xml 中配置 bean;
<?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"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd
">
<!--配置实例工厂对象-->
<bean id="carFactory" class="com.trainingl.Factory.InstanceCarFactory"></bean>
<!--通过实例工厂对象创建car对象-->
<bean id="car2" factory-bean="carFactory" factory-method="getCar">
<constructor-arg value="2"></constructor-arg>
</bean>
</beans>
factory-bean
指向实例化的工厂对象;factory-method
指向实例工厂对象的非静态方法;constructor-arg
的 value 属性为调用非静态方法所传的参数;
第三步:在测试类中直接获取 car2 对象;
package com.trainingl.test;
import com.trainingl.entity.Car;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test2 {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
Car car = (Car)applicationContext.getBean("car2");
System.out.println(car);
}
}
对比两种方式的区别:
-
静态工厂方法的方式创建 Car 对象,不需要实例化工厂对象,因为静态工厂的静态方法不需要创建对象即可调用,所以 spring.xml 只需要配置一个 Car bean,而不需要配置工厂 bean。
-
实例工厂方法创建 car 对象,必须先实例化工厂对象,因为调用的非静态方法,必须通过对象调用,不能直接通过类来调用,所以 spring.xml 中需要先配置工厂 bean,再配置 Car 的 bean。
两种方式的区别,本质上还是静态方法与非静态方法调用的不同。