定义:
工厂方法模式(Factory Method Pattern)是一种创建型设计模式,用于解决对象创建的问题。它定义了一个创建对象的接口,但让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。
工厂方法模式的关键组成部分包括:
- 抽象创建者(Creator):
- 定义了一个工厂方法,通常是一个抽象方法,用于创建产品对象。创建者通常包含依赖于抽象产品的代码。
- 具体创建者(Concrete Creator):
- 实现了抽象创建者定义的工厂方法,用于返回一个具体产品的实例。每个具体创建者都负责创建一个特定类型的产品。
- 抽象产品(Product):
- 定义了产品的接口。在抽象创建者的代码中,所有对产品的引用都使用这个接口。
- 具体产品(Concrete Product):
- 实现了抽象产品定义的接口。工厂方法返回的产品实例实际上是某个具体产品对象。
解决的问题:
- 创建对象的灵活性:
- 当一个类不知道它所必须创建的对象的类的时候。工厂方法模式允许类把实例化延迟到子类进行,这提供了更大的灵活性。
- 产品类扩展的便利性:
- 当一个类希望由其子类来指定创建的对象时。通过定义工厂方法,子类可以覆盖这个方法以改变创建对象的类型。
- 解耦产品的具体实现和创建过程:
- 工厂方法模式使得客户代码与产品的具体实现解耦,客户代码通过工厂接口创建产品,无需关心产品的具体实现。
- 单一职责原则:
- 工厂方法模式可以将产品的创建职责集中到不同的工厂类中,每个工厂类负责创建一种具体产品,这符合单一职责原则。
- 开闭原则:
- 系统更容易扩展,可以引入新的具体产品和具体工厂类,而无需修改现有代码。这符合开闭原则,即对扩展开放,对修改封闭
使用场景:
- 不同环境下创建不同实例:
- 当对象的创建需要基于不同的环境或条件时,例如不同的配置、操作系统或者不同的资源要求。
- 明确分离客户端和产品实现:
- 当需要明确区分客户端和产品的具体实现,使得客户端不依赖于产品实现的具体类时。
- 单个类负责多个不同对象的创建:
- 当一个类需要创建多种类型的对象,且这些对象有共同的基类或接口时,但同时又需要保持类的职责单一。
- 扩展产品类时避免影响客户端:
- 当系统要求提供扩展产品类的能力,而不希望这些更改影响到已有的客户端代码时。
- 需要封装对象的创建过程:
- 当对象的创建过程需要被封装起来,以便提供更多的复用性和灵活性时。
- 类的实例化过程复杂或有特殊要求:
- 当创建对象的过程很复杂,如涉及到复杂的初始化步骤,或者需要进行资源回收等。
示例代码:
// 产品接口
public interface Product {void use();
}// 具体产品
public class ConcreteProductA implements Product {@Overridepublic void use() {System.out.println("Using ConcreteProductA");}
}public class ConcreteProductB implements Product {@Overridepublic void use() {System.out.println("Using ConcreteProductB");}
}// 创建者/工厂接口
public interface Factory {Product createProduct();
}// 具体创建者/工厂
public class ConcreteFactoryA implements Factory {@Overridepublic Product createProduct() {return new ConcreteProductA();}
}public class ConcreteFactoryB implements Factory {@Overridepublic Product createProduct() {return new ConcreteProductB();}
}
主要符合的设计原则:
- 开闭原则(Open-Closed Principle):
- 工厂方法模式非常符合开闭原则。它允许系统在不修改现有代码的情况下引入新的产品类型。当系统需要扩展新的产品时,只需要添加相应的具体工厂类和产品类即可。
- 单一职责原则(Single Responsibility Principle):
- 在工厂方法模式中,每个具体工厂类只负责创建单一类型的产品。这符合单一职责原则,因为每个类都只负责一个具体的创建任务。
- 依赖倒转原则(Dependency Inversion Principle):
- 工厂方法模式实现了依赖倒转原则,因为客户代码依赖于抽象接口(产品接口和工厂接口),而不是具体的类实现。这意味着客户代码并不依赖于具体的产品实例化逻辑。
工厂方法模式通过定义一个用于创建对象的接口,让子类决定实例化哪个类,从而使一个类的实例化延迟到其子类,提高了代码的灵活性和可扩展性。同时,它支持良好的封装性,客户代码仅通过接口与工厂交互,无需关心具体的产品实现细节。
在JDK中的应用:
java.util.Calendar
类:Calendar.getInstance()
是一个工厂方法,它根据当前的时间和默认时区返回一个Calendar
的具体实例。此方法隐藏了具体Calendar
子类的创建细节。
java.util.ResourceBundle
类:ResourceBundle.getBundle()
方法是一个工厂方法,用于根据给定的基础名和目标区域设置加载资源束。这个方法封装了资源束对象的选择和加载过程。
java.nio.charset.Charset
类:Charset.forName()
方法根据字符集的名称返回一个Charset
对象。该方法是一个工厂方法,它隐藏了字符集对象的实际创建过程。
java.sql.DriverManager
类:- 在JDBC API中,
DriverManager.getConnection()
方法根据数据库URL、用户名和密码返回一个Connection
对象。这是工厂方法模式的一个应用,它封装了数据库连接对象的创建细节。
- 在JDBC API中,
java.lang.NumberFormat
类:NumberFormat
类提供了多个工厂方法(如getNumberInstance()
,getCurrencyInstance()
)来获取不同格式化风格的NumberFormat
对象。
在Spring中的应用:
- Spring的BeanFactory:
BeanFactory
是Spring框架的核心接口,它提供了高级的配置机制来管理任何类型的对象。BeanFactory
作为一个对象工厂,它为依赖注入(DI)提供了支持,管理应用程序中定义的bean,并在需要时创建和返回bean实例。
- ApplicationContext:
ApplicationContext
是BeanFactory
的子接口,提供了更丰富的功能。它不仅用于加载Bean定义,还提供了国际化、事件传播、资源加载等其他功能。在Spring中,ApplicationContext
通常用作Bean工厂。
- FactoryBean:
- 在Spring中,
FactoryBean
接口用于定义一个Bean,它本身作为工厂来生产其他对象。这个接口允许实现类在Spring容器中定义复杂的初始化逻辑。
- 在Spring中,
- 静态工厂方法和实例工厂方法:
- Spring允许通过静态工厂方法或实例工厂方法来创建Bean。这在Spring的配置中通过
<bean>
元素的factory-method
属性来实现。
- Spring允许通过静态工厂方法或实例工厂方法来创建Bean。这在Spring的配置中通过
- ServiceLocatorFactoryBean:
- 这是一个特殊的
FactoryBean
,用于定义服务定位器。它可以用来抽象对服务接口的访问,使得客户端代码不需要直接与服务实现类耦合。
- 这是一个特殊的