设计模式中的工厂模式主要分为三种:简单工厂模式(Simple Factory Pattern)、工厂方法模式(Factory Method Pattern)和抽象工厂模式(Abstract Factory Pattern)。
下面是对这三种工厂模式的详细介绍和对比。
一、简单工厂模式
-
定义:简单工厂模式又称静态工厂方法模型,它属于类创建型模式。在简单工厂模式中,可以根据参数的不同返回不同类的实例。简单工厂专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。
-
结构:
- 工厂角色:工厂类,是简单工厂模式的核心,负责实现创建所有实例的内部逻辑。工厂类可以直接被外界调用,创建所需的产品对象。
- 抽象产品角色:简单工厂模式所创建的所有对象的父类,负责描述所有实例所共有的公共接口。
- 具体产品角色:简单工厂模式所创建的具体实例对象,这些具体的产品往往都拥有共同的父类。
-
优缺点:
- 优点:
- 工厂类包含必要的逻辑判断,可以决定在什么时候创建哪一个产品的实例,客户端可以免除直接创建产品对象的职责。
- 客户端无需知道所创建具体产品的类名,只需知道参数即可。
- 可以引入配置文件,在不修改客户端代码的情况下更换和添加新的具体产品类。
- 缺点:
- 工厂类集中了所有产品的创建逻辑,职责过重,一旦异常,整个系统将受影响。
- 使用简单工厂模式会增加系统中类的个数(引入新的工厂类),增加系统的复杂度和理解难度。
- 系统扩展困难,一旦增加新产品不得不修改工厂逻辑,在产品类型较多时,可能造成逻辑过于复杂。
- 简单工厂模式使用了静态工厂方法,造成工厂角色无法形成基于继承的等级结构。
- 优点:
-
适用环境:
- 工厂类负责创建的对象比较少,不会造成工厂方法中的业务逻辑过于复杂。
- 客户端只知道传入工厂类的参数,对如何创建对象不关心。
代码示例:
// 抽象产品类
public abstract class Vedio {public abstract void produce();
}// 具体产品类1
public class JavaVedio extends Vedio {@Overridepublic void produce() {System.out.println("录制 Java 视频");}
}// 具体产品类2
public class PythonVedio extends Vedio {@Overridepublic void produce() {System.out.println("录制 Python 视频");}
}// 工厂类
public class VedioFactory {public Vedio getVedio(String type) {Vedio vedio = null;if ("Java".equals(type)) {vedio = new JavaVedio();} else if ("Python".equals(type)) {vedio = new PythonVedio();}return vedio;}
}// 测试类
public class Main {public static void main(String[] args) {Vedio javaVedio = new VedioFactory().getVedio("Java");javaVedio.produce();Vedio pythonVedio = new VedioFactory().getVedio("Python");pythonVedio.produce();}
}
二、工厂方法模式
-
定义:工厂方法模式又称多态性工厂模式,属于设计模式三大分类中的创建型模式。它定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个,也就是说工厂方法让实例化推迟到子类。
-
结构:
- 抽象工厂角色:成为抽象工厂类,仅负责给出具体工厂子类必须实现的接口,而不接触哪一个产品应当被实例化这种细节。
- 具体工厂角色:实现抽象工厂类中的抽象方法,完成具体产品的创建。
- 抽象产品角色:定义了产品的规范,描述了产品的主要特性和功能。
- 具体产品角色:实现了抽象产品角色所定义的接口,由具体工厂来创建。
-
优缺点:
- 优点:
- 用户只需要关系所需产品对应的工厂,无须关心创建细节。
- 加入新产品符合开闭原则,提高可扩展性。
- 缺点:
- 类的个数容易过多,增加复杂度。
- 增加了系统的抽象性和理解难度。
- 优点:
-
应用场景:
- 客户只知道创建产品的工厂名,而不知道具体的产品名。
- 创建对象的任务由多个具体子工厂中的某一个完成,而抽象工厂只提供创建产品的接口。
- 客户不关心创建产品的细节,只关心产品的品牌。
代码示例:
// 抽象产品类
public abstract class Vedio {public abstract void produce();
}// 具体产品类1
public class JavaVedio extends Vedio {@Overridepublic void produce() {System.out.println("录制 Java 视频");}
}// 具体产品类2
public class PythonVedio extends Vedio {@Overridepublic void produce() {System.out.println("录制 Python 视频");}
}// 抽象工厂类
public abstract class VedioFactory {public abstract Vedio getVedio();
}// 具体工厂类1
public class JavaVedioFactory extends VedioFactory {@Overridepublic Vedio getVedio() {return new JavaVedio();}
}// 具体工厂类2
public class PythonVedioFactory extends VedioFactory {@Overridepublic Vedio getVedio() {return new PythonVedio();}
}// 测试类
public class Main {public static void main(String[] args) {VedioFactory javaFactory = new JavaVedioFactory();Vedio javaVedio = javaFactory.getVedio();javaVedio.produce();VedioFactory pythonFactory = new PythonVedioFactory();Vedio pythonVedio = pythonFactory.getVedio();pythonVedio.produce();}
}
三、抽象工厂模式
-
定义:抽象工厂模式是一种为访问类提供一个创建一组相关或相互依赖对象的接口,且访问类无须指定所要产品的具体类就能得到同族的不同等级的产品的模式结构。它是工厂方法模式的升级版本,工厂方法模式只生产一个等级的产品,而抽象工厂模式可生产多个等级的产品。
-
结构:
- 抽象工厂角色:提供了创建产品的接口,它包含多个创建产品的方法,可以创建多个不同等级的产品。
- 具体工厂角色:实现抽象工厂中的多个抽象方法,完成具体产品的创建。
- 抽象产品角色:定义了产品的规范,描述了产品的主要特性和功能。抽象工厂模式有多个抽象产品。
- 具体产品角色:实现了抽象产品角色所定义的接口,由具体工厂来创建,它与具体工厂之间是多对一的关系。
-
优缺点:
- 优点:
- 具体产品在应用层代码隔离,无须关心创建细节。
- 将一个系列的产品族统一到一起创建。
- 缺点:
- 规定了所有可能被创建的产品集合,产品族中扩展新的产品困难,需要修改抽象工厂的接口。
- 增加了系统的抽象性和理解难度。
- 优点:
-
使用条件:
- 系统中有多个产品族,每个具体工厂创建同一族但属于不同等级结构的产品。
- 系统一次只可能消费其中某一族产品,即同族的产品一起使用。
代码示例:
// 抽象产品类1
public abstract class Fridge {public abstract void produce();
}// 具体产品类1
public class MideaFridge extends Fridge {@Overridepublic void produce() {System.out.println("生产美的冰箱");}
}// 具体产品类2
public class GreeFridge extends Fridge {@Overridepublic void produce() {System.out.println("生产格力冰箱");}
}// 抽象产品类2
public abstract class AirConditioner {public abstract void produce();
}// 具体产品类3
public class MideaAirConditioner extends AirConditioner {@Overridepublic void produce() {System.out.println("生产美的空调");}
}// 具体产品类4
public class GreeAirConditioner extends AirConditioner {@Overridepublic void produce() {System.out.println("生产格力空调");}
}// 抽象工厂接口
public interface Factory {Fridge getFridge();AirConditioner getAirConditioner();
}// 具体工厂类1
public class MideaFactory implements Factory {@Overridepublic Fridge getFridge() {return new MideaFridge();}@Overridepublic AirConditioner getAirConditioner() {return new MideaAirConditioner();}
}// 具体工厂类2
public class GreeFactory implements Factory {@Overridepublic Fridge getFridge() {return new GreeFridge();}@Overridepublic AirConditioner getAirConditioner() {return new GreeAirConditioner();}
}// 测试类
public class Main {public static void main(String[] args) {Factory mideaFactory = new MideaFactory();Fridge mideaFridge = mideaFactory.getFridge();AirConditioner mideaAirConditioner = mideaFactory.getAirConditioner();mideaFridge.produce();mideaAirConditioner.produce();Factory greeFactory = new GreeFactory();Fridge greeFridge = greeFactory.getFridge();AirConditioner greeAirConditioner = greeFactory.getAirConditioner();greeFridge.produce();greeAirConditioner.produce();}
}
四、对比
-
结构差异:
- 简单工厂模式只有一个工厂类,负责创建所有产品。
- 工厂方法模式有一个抽象工厂接口和多个具体工厂类,每个具体工厂类负责创建一种产品。
- 抽象工厂模式有一个抽象工厂接口和多个具体工厂类,但每个具体工厂类负责创建一组相关或相互依赖的产品。
-
扩展性:
- 简单工厂模式扩展新产品时需要修改工厂类的逻辑,不符合开闭原则。
- 工厂方法模式扩展新产品时只需添加新的具体产品类和对应的具体工厂类,符合开闭原则。
- 抽象工厂模式扩展新产品族时需要修改抽象工厂接口和具体工厂类,但扩展同一产品族内的新产品时只需添加新的具体产品类,部分符合开闭原则。
-
复杂度:
- 简单工厂模式结构相对简单,但工厂类职责过重。
- 工厂方法模式增加了类的个数,但降低了类的耦合度。
- 抽象工厂模式结构最复杂,但提供了更高的灵活性和可扩展性。
五、工厂模式在Spring框架中的应用
工厂模式(Factory Pattern)作为创建型模式,其核心思想是通过定义一个接口来创建对象,并让子类决定实例化哪个类。这种模式在Spring框架中得到了广泛的应用,特别是在其核心的控制反转(IoC)容器中。
以下是对工厂模式在Spring框架中应用的介绍:
一些常见的应用:
-
BeanFactory:
- Spring最基础的容器,采用了工厂方法模式来创建和管理bean。
- 在Spring 2.x及以前版本,BeanFactory常用于对象的实例化,尤其是对于需要延迟加载的bean(懒加载)。
- BeanFactory接口定义了用于获取bean的基本方法,如getBean(),客户端可以通过这个方法来请求容器中的bean。
-
ApplicationContext:
- Spring的核心容器,继承自BeanFactory,提供了更多的功能,如事件传播、国际化支持、AOP等。
- ApplicationContext也是通过工厂方法模式来创建和管理bean的。它会根据配置文件(XML配置或注解配置)动态地创建bean并管理它们的生命周期。
-
FactoryBean接口:
- 用于通过工厂类动态创建复杂的对象或自定义bean的创建逻辑。
- FactoryBean接口的核心方法是getObject(),它允许开发者在bean的实例化过程中执行自定义逻辑。
- 例如,FactoryBean常常用于创建数据库连接池或外部资源的管理。
实现说明:
-
简单工厂模式的应用:
- 在Spring框架中,简单工厂模式常用于根据配置文件或者运行时参数来动态地创建对象。
- 例如,可以定义一个简单工厂类CarFactory,根据传入的参数来创建不同类型的汽车对象。
-
工厂方法模式的应用:
- 在Spring框架中,工厂方法模式常用于创建复杂对象或者对象组合,以便更好地管理对象的创建逻辑。
- 例如,可以定义一个抽象的数据库连接工厂ConnectionFactory,并在子类中实现具体的连接创建逻辑。
-
抽象工厂模式的应用:
- 在Spring框架中,抽象工厂模式常用于创建具有不同主题或风格的对象组合。
- 例如,可以定义一个抽象的主题工厂ThemeFactory,用于创建按钮和文本框等相关的UI组件。
优势:
- 解耦:通过工厂模式,Spring框架解耦了客户端与对象的依赖关系,使得客户端不再关心具体的类实现,而只需要依赖工厂接口来获取实例。
- 灵活性:工厂模式使得对象的创建变得非常灵活和动态,可以根据配置文件或注解动态配置bean。
- 可扩展性:通过工厂模式,Spring框架可以轻松地添加新的bean类型,而无需修改现有的客户端代码
六、拓展:Spring中的BeanFactory与FactoryBean
BeanFactory和FactoryBean都是Spring框架中重要的概念,它们在Spring的IoC(控制反转)容器中扮演着不同的角色。下面将详细介绍这两个概念,以及它们之间的区别与联系。
BeanFactory
- 定义与角色:
- BeanFactory是Spring框架中的一个接口,它是Spring IoC容器的基础。
- 它负责创建、配置和管理Bean对象,是Spring容器的基本规范和行为定义。
- 主要功能:
- 提供Bean的创建、配置、初始化和销毁等基本操作。
- 可以根据配置文件(如XML文件)或注解来创建并管理Bean实例。
- 提供了各种方法来获取和操作Bean实例,如
getBean()
方法。
- 实现类:
- 常见的实现类有
XmlBeanFactory
(在Spring 3.x之前使用较多)和DefaultListableBeanFactory
等。 XmlBeanFactory
通过解析XML配置文件来创建和管理Bean。DefaultListableBeanFactory
则提供了更丰富的功能,是Spring默认的BeanFactory实现。
- 常见的实现类有
FactoryBean
- 定义与角色:
- FactoryBean是Spring框架中的一个特殊接口,用于创建复杂的或可配置的Spring Bean实例。
- 它本身也是一个Bean,但与其他Bean不同的是,它通过实现
FactoryBean
接口来定义自己的创建逻辑。
- 主要功能:
- 允许在创建Bean时进行更多的自定义操作,如依赖注入、配置读取等。
- 可以隐藏实际创建Bean的复杂逻辑,对外提供一个简单的接口。
- 提供了
getObject()
方法来返回创建的Bean实例,以及getObjectType()
和isSingleton()
方法来描述Bean的特性和类型。
- 应用场景:
- 常用于创建数据库连接池、外部资源管理、复杂对象组合等场景。
- 在AOP(面向切面编程)中,
ProxyFactoryBean
等FactoryBean实现类用于创建代理对象。
区别与联系
- 区别:
- 角色与功能:BeanFactory是Spring IoC容器的基础接口,负责Bean的创建、配置和管理;而FactoryBean是一个特殊的Bean,用于定义自己的创建逻辑和返回创建的Bean实例。
- 使用方式:BeanFactory通常作为Spring容器的入口点,用于获取和管理Bean;而FactoryBean则通过实现接口并在配置文件中声明来使用,以创建复杂的Bean实例。
- 灵活性:FactoryBean提供了更高的灵活性,允许在Bean创建过程中进行更多的自定义操作;而BeanFactory则更侧重于提供基本的容器功能。
- 联系:
- 都属于Spring框架:BeanFactory和FactoryBean都是Spring框架中的概念,它们共同构成了Spring IoC容器的核心部分。
- 相互协作:在Spring容器中,BeanFactory负责管理和维护Bean的实例;而FactoryBean则可以在Bean的创建过程中提供额外的自定义逻辑。因此,它们在一定程度上是相互协作的。
- 综上所述,BeanFactory和FactoryBean在Spring框架中扮演着不同的角色,但它们共同构成了Spring IoC容器的核心部分。了解它们之间的区别与联系有助于更好地理解和使用Spring框架。