工厂模式的优缺点和使用场景
一、工厂模式概念
工厂模式是一种常见的设计模式,用于创建对象的实例化过程。它通过定义一个公共的接口或抽象类来创建对象,而不是直接使用new关键字实例化对象。这样可以将对象的创建和使用解耦,提高代码的灵活性和可维护性。
二、什么情况下使用工厂模式
如果对象可以直接new 则可以不用工厂模式.
如果有些对象不能直接new 需要生产资料的支持 则建议使用工厂模式实现
典型代表: 数据库连接/数据源等
如果创建对象比较复杂时,也可以使用工厂模式进行简化.
三、实现工厂模式的思路是
1.定义抽象产品(Abstract Product):创建一个接口或抽象类,定义产品的公共方法。
2.创建具体产品(Concrete Product):实现抽象产品接口或继承抽象产品抽象类,实现具体产品的具体逻辑。
3.定义抽象工厂(Abstract Factory):创建一个接口或抽象类,定义创建产品的方法。
4.创建具体工厂(Concrete Factory):实现抽象工厂接口或继承抽象工厂抽象类,实现创建具体产品的方法。
5.在客户端中使用工厂:通过调用具体工厂的方法来创建具体产品的对象,而不直接使用new关键字。
四、需要注意的地方
工厂只负责创建对象,不应该有别的业务。
客户端应该通过抽象工厂或者工厂接口来获取产品对象,而不是直接依赖具体工厂类。这样可以降低客户端与具体工厂类之间的耦合度,提高代码的灵活性和可维护性
五、优缺点
优点 | 缺点 |
封装对象的创建过程,降低客户端与产品类之间的耦合度 | 增加系统的复杂性,引入额外的类和对象 |
提供灵活性和可扩展性,方便添加新的产品类型 | 不易于扩展新的产品族,需要修改抽象工厂接口和具体工厂类 |
隐藏实现细节,保护产品的安全性和稳定性 | 需要额外的工厂类,增加了系统的复杂性 |
代替单例模式
单例模式的核心要求就是在内存中只有一个对象,通过工厂方法模式也可以只在内 存中生产一个对象
六、工厂模式的分类(以Spring管理对象为例)
1.静态工厂(简单工厂模式)
规则:有些对象不能直接new,利用工厂类创建。
简单工厂模式也叫静态工厂模式,就是工厂类一般是使用静态方法,通过接收的参数的不同来返回不同的实例对象。
public interface Car {
void run();
}
public class AdCarImpl implements Car{
@Override
public void run() {
System.out.println("奥迪在跑!");
}
}
public class BydCarImpl implements Car{
@Override
public void run() {
System.out.println("比亚迪在跑!");
}
}
//静态工厂模式(方式一)
public class CarFactory {
public static Car getCar(String type){
if ("奥迪".equals(type)){
return new AdCarImpl();
}else if ("比亚迪".equals(type)) {
return new BydCarImpl();
}else {
return null;
}
}
//静态工厂模式(方式二)
/*public static Car getAdCar(){
return new AdCarImpl();
}
public static Car getBydCar(){
return new BydCarImpl();
}*/
}
测试
public class TestCar {
public static void main(String[] args) {
Car car = CarFactory.getCar("比亚迪");
car.run();
}
}
缺点
对于增加新产品,不修改代码的话,是无法扩展的。违反了开闭原则(对扩展开放;对修改封闭)。
2.springIOC-静态工厂
需求:想让Spring容器管理Calendar对象 获取时间.
编写静态工厂代码
import java.util.Calendar;
public class StaticFactory {
//可以对外暴露静态方法 static
public static Calendar getCalendar(){
//至于如何实例化对象 代码自己维护
return Calendar.getInstance();
}
}
编写xml配置文件
<!--使用静态工厂 实例化对象 交给spring容器管理-->
<!-- 1.静态工厂(不需要创建工厂本身)factory
2.factory-method 指定哪个方法是工厂方法
3.class:指定静态工厂全类名-->
<bean id="calendar1"
class="com.atguigu.factory.StaticFactory" factory-method="getCalendar"/>
测试
//测试静态工厂模式
@Test
public void test05_static(){
ApplicationContext context =
new ClassPathXmlApplicationContext("applicationContext.xml");
Calendar calendar1 = context.getBean("calendar1", Calendar.class);
System.out.println(calendar1.getTime());
}
3.SpringIOC-实例工厂
其实实例工厂和静态工厂差不多,只不过静态工厂的服务是静态的,提供的方法是static的,而实例工厂提供的方法服务是非static的,实例工厂相对比较灵活。
1> 编辑工厂对象
public class MyFactory{
public MyFactory(){
System.out.println("实例工厂对象创建");
}
public Calendar getCalender(){
//实例化对象(伪代码)
return Calendar.getInstance();
}
}
2> 编辑配置文件
<!--先配置出实例工厂对象-->
<bean id="myfactory" class="com.yl.factory.MyFactory"/>
<!--通过实例方法配置bean
factory-bean:指定使用哪个工厂(实例工厂)
factory-method 指定哪个方法是工厂方法-->
<bean id="Calender" factory-bean="myfactory" factory-method="getCalender"/>
3> 测试
public class TestSpring {
@Test
public void test01_factory(){
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
MyFactory myFactory = context.getBean(MyFactory.class);
Calendar myFactoryCalender = myFactory.getCalender();
System.out.println("myFactoryCalender = " + myFactoryCalender);
}
}
4.springIOC中自带的工厂接口
1> 编辑工厂类
package com.yl.factory;
import org.springframework.beans.factory.FactoryBean;
import java.util.Calendar;
/**
* @Author yl
* @Date 2023/8/29 19:17
* @Version 1.0
*/
public class MySpringFactory implements FactoryBean<Calendar>{
public MySpringFactory(){
System.out.println("我是SpringFactory的构造方法");
}
/**
* 工厂方法 spring自动调用
* 将对象的返回值 交给spring容器管理
* @return 返回创建的对象
* @throws Exception
*/
@Override
public Calendar getObject() throws Exception {
return Calendar.getInstance();
}
/**
* @return 返回对象的类型
*/
@Override
public Class<?> getObjectType() {
return Calendar.class;
}
/**
* 是否为单例对象
* 单例: spring容器一个类型有且只有一个对象
* 多例对象: 用户一次创建一次
* @return true是单例
*/
@Override
public boolean isSingleton() {
return true;
}
}
2> 编辑配置对象
<!-- FactoryBean *(是Spring规定的一个接口);
只要是这个接口的实现类,Spring都认为是一个工厂
ioc容器启动不会创建实例
FactoryBean:获取的时候才会创建对象-->
<bean id="Calendar1" class="com.yl.factory.MySpringFactory"/>
3> 测试
@Test
public void test_springfactory(){
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
Calendar calendar = context.getBean("Calendar1", Calendar.class);
System.out.println(calendar.getTime());
}
七、总结
<!--
spring管理的对象 叫做bean
id="唯一标识符不能重复"
class="创建对象时使用的类型"
spring创建对象一般都是反射机制,反射必然调用无参构造
-->
在spring中一般使用最后一种获取对象方式,流程如下:
方式 | 描述 |
依赖注入 | 使用依赖注入将对象的创建和依赖关系的管理交给Spring容器来处理,实现了工厂模式的封装和灵活性。 |
IoC容器 | Spring的IoC容器负责管理对象的生命周期和依赖关系,通过配置文件或注解告诉容器需要创建哪些对象以及它们之间的依赖关系。 |
@Bean注解 | 在配置类中使用@Bean注解标记方法为工厂方法,负责创建并返回对象实例。Spring容器会在需要时调用这些方法来创建对象,并将其纳入管理。 |
FactoryBean接口 | 实现FactoryBean接口来自定义工厂类,控制对象的创建过程。FactoryBean接口的实现类既可以作为普通的Bean被注入和使用,也可以作为工厂创建其他对象。 |
@Qualifier注解 | 当存在多个具有相同类型的Bean时,使用@Qualifier注解指定所需的具体Bean,实现根据需要选择不同实例化策略。 |