什么是工厂方法模式?
工厂方法模式是一种创建型设计模式,它定义了一个用于创建对象的接口(工厂方法),但让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。
简单来说,它提供了一种封装对象创建过程的方式,将实际的对象创建逻辑推迟到子类中进行。
核心思想
想象一下,你有一个类需要创建一个产品对象,但具体创建哪种产品在编写该类时并不确定,或者希望由子类来决定。这时,你可以在父类中定义一个抽象的“工厂方法”,该方法返回一个产品类型的对象。然后,在不同的子类中实现这个工厂方法,让每个子类根据自身需求创建并返回具体的产品实例。
优点
- 解耦 (Decoupling):
- 将产品的创建逻辑从使用产品的代码(客户端)中分离出来。
- 客户端只需要知道产品的抽象接口,而不需要关心具体的实现类是如何被创建的。
- 同时,创建者(父类)也只依赖于产品接口。
- 灵活性和可扩展性 (Flexibility & Extensibility):
- 遵循“开闭原则”(Open/Closed Principle)。
- 当需要引入新的产品类型时,只需要添加新的具体产品类和对应的具体工厂子类,而无需修改现有的工厂父类或客户端代码。
- 单一职责原则 (Single Responsibility Principle):
- 将对象创建的逻辑集中到工厂方法或具体的工厂子类中,使得代码结构更清晰,职责更明确。
使用场景
- 当一个类不知道它所必须创建的对象的类时。
- 当一个类希望由它的子类来指定它所创建的对象时。
- 当你希望将创建对象的逻辑局部化,以便在未来更容易修改或替换时。
- Android 中的场景:
- 创建不同类型的
ViewModel:ViewModelProvider.Factory就是工厂方法模式的一个典型应用,它允许你自定义ViewModel的创建过程,特别是需要传递参数或依赖注入时。 - 根据不同的条件或配置创建不同类型的
Fragment或Dialog。 - 在自定义
RecyclerView.Adapter中,根据viewType创建不同类型的ViewHolder(虽然onCreateViewHolder更接近抽象工厂的变体,但其“延迟到子类决定具体类型”的思想与工厂方法类似)。 - 提供库或框架给用户使用时,允许用户通过实现工厂方法来扩展或替换某些组件的创建。
UML图
下面是工厂方法模式的一个典型 UML 结构图,以我们稍后将要实现的“日志记录器”为例:
- Logger (Product): 定义了日志记录器对象的接口。
- FileLogger, DatabaseLogger, ConsoleLogger (ConcreteProduct): 则是实现了
Logger接口的具体产品类。
- LoggerFactory (Creator): 声明了工厂方法
createLogger(),它返回一个Logger对象。LoggerFactory也可以定义一个使用Logger对象的方法,如logMessage()。
- FileLoggerFactory, DatabaseLoggerFactory, ConsoleLoggerFactory (ConcreteCreator): 实现了
createLogger()方法,以返回具体日志记录器的实例。
代码示例
日志记录器示例
在这个例子中:
- 客户端代码 (
main函数) 决定使用哪个工厂 (FileLoggerFactory,DatabaseLoggerFactory, etc.)。
- 客户端通过调用工厂的
logMessage方法来记录日志。
logMessage方法内部调用了抽象的createLogger方法,具体由哪个子工厂实现,就创建哪个具体的Logger实例。
- 客户端代码与具体的
Logger实现(FileLogger,DatabaseLogger)完全解耦,只依赖于LoggerFactory和Logger接口。
Android ViewMode示例
总结
- 工厂方法模式通过将对象创建过程延迟到子类,有效地解耦了对象的创建和使用,提高了系统的灵活性和可扩展性。
- 当需要创建的对象类型可能变化,或者希望由子类来决定具体创建哪个对象时,工厂方法模式是一个非常好的选择。
- 理解并运用工厂方法模式,可以帮助我们更好地管理对象的创建,尤其是在处理依赖注入和复杂对象初始化时。
- Author:CoderWdd
- URL:https://www.wuinsights.top//article/0044562b-de76-4bc9-b3b2-36d65afbcff2
- Copyright:All articles in this blog, except for special statements, adopt BY-NC-SA agreement. Please indicate the source!
Relate Posts