工厂方法模式(Factory Method Pattern) 是一种创建型设计模式,它定义了一个创建对象的接口,但由子类决定实例化哪个类。工厂方法模式使得类的实例化推迟到子类中进行,从而达到解耦的目的。工厂方法模式的核心思想是把实例化对象的工作交给子类,而不是由客户端代码直接控制,这样可以使得代码更加灵活和可扩展。
1. 适用场景
工厂方法模式适用于以下情况:
- 当一个类无法预见它所需要创建的对象类型时,或是希望在类内创建多个类型的对象时。
- 当一个类希望通过其子类来指定创建对象的类型时。
- 当你想要避免在代码中直接使用
new
关键字来实例化对象,以便将实例化的责任推迟到子类中时。
2. 组成部分
工厂方法模式包含以下几个角色:
- 产品(Product):定义了工厂方法所创建的对象的接口。
- 具体产品(ConcreteProduct):实现了
Product
接口的具体类,代表具体的产品。 - 工厂(Creator):定义了一个工厂方法,声明返回
Product
对象的接口。 - 具体工厂(ConcreteCreator):实现了
Creator
中的工厂方法,负责实例化具体的产品对象。
3. 结构图
+----------------+
| Creator | <-- Abstract Factory (工厂)
+----------------+
| + factoryMethod()| --> 工厂方法接口
+----------------+
^
|
+------------------+
| ConcreteCreator | <-- 具体工厂
+------------------+
| + factoryMethod() |
+------------------+
^
|
+-------------+
| Product | <-- 产品接口
+-------------+
| + doSomething() |
+-------------+
^
|
+-------------------+
| ConcreteProduct | <-- 具体产品
+-------------------+
| + doSomething() |
+-------------------+
4. 代码示例
假设我们有一个图形(Shape)接口,具体的图形类有圆形(Circle)和矩形(Rectangle)。我们希望通过工厂方法来创建这些图形对象,而不是直接在代码中用new
来实例化它们。
1. 定义产品接口(Product)
// 产品接口:Shape
public interface Shape {
void draw(); // 产品的具体方法
}
2. 具体产品类(ConcreteProduct)
// 具体产品1:Circle
public class Circle implements Shape {
@Override
public void draw() {
System.out.println("Drawing Circle");
}
}
// 具体产品2:Rectangle
public class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Drawing Rectangle");
}
}
3. 工厂接口(Creator)
// 工厂接口:Creator
public abstract class ShapeFactory {
// 工厂方法:返回一个Shape类型的对象
public abstract Shape createShape();
}
4. 具体工厂类(ConcreteCreator)
// 具体工厂1:CircleFactory
public class CircleFactory extends ShapeFactory {
@Override
public Shape createShape() {
return new Circle(); // 返回一个Circle对象
}
}
// 具体工厂2:RectangleFactory
public class RectangleFactory extends ShapeFactory {
@Override
public Shape createShape() {
return new Rectangle(); // 返回一个Rectangle对象
}
}
5. 客户端代码(Client)
public class Client {
public static void main(String[] args) {
// 使用工厂来创建对象,而不是直接new
ShapeFactory circleFactory = new CircleFactory();
Shape circle = circleFactory.createShape();
circle.draw(); // 输出:Drawing Circle
ShapeFactory rectangleFactory = new RectangleFactory();
Shape rectangle = rectangleFactory.createShape();
rectangle.draw(); // 输出:Drawing Rectangle
}
}
5. 运行结果
Drawing Circle
Drawing Rectangle
6. 总结
- 工厂方法模式定义了一个创建对象的接口,但由子类决定实例化哪一个类。这样可以将对象的创建和具体类的使用解耦,提高代码的灵活性。
- 适用场景:
- 当类不知道它需要创建的对象的具体类型时。
- 当类希望由其子类来指定所创建的对象类型时。
- 当类希望将对象的创建推迟到子类中时。
- 优点:
- 可以扩展新的具体产品,只需要增加新的具体工厂类。
- 客户端代码不依赖于具体的类,增加了代码的可维护性和可扩展性。
- 可以将对象的创建和使用分离,提高了代码的灵活性。
- 缺点:
- 每增加一种产品,就需要增加一个具体工厂类,可能导致类的数量增加。
- 客户端需要了解具体的工厂类,从而导致一定程度的耦合。
7. 与简单工厂模式的对比
简单工厂模式(Simple Factory Pattern)和工厂方法模式有一定的相似性,都用于创建对象,但两者有以下区别:
- 简单工厂模式:通过一个工厂类根据传入的参数来决定实例化哪种具体产品,所有的产品创建都集中在一个工厂类中。客户端直接依赖于这个工厂类。
- 工厂方法模式:将创建产品的责任分散到多个具体工厂中,每个工厂负责创建一种产品。客户端通过工厂接口来调用,工厂的选择交给子类来实现,从而解耦。
8. 扩展:工厂方法模式的优势
- 灵活性:当需要扩展新的产品时,只需要增加新的具体工厂类和具体产品类,而不需要修改现有的代码。
- 减少耦合:工厂方法模式将对象的创建与使用分离,客户端无需了解具体产品的创建过程。
- 遵循开闭原则:通过扩展来增加新的功能,而不是修改原有代码,符合开闭原则。
9. 典型应用场景
- 日志系统:不同的日志输出方式(控制台、文件、数据库等)可以通过不同的工厂类来创建,客户端只需要依赖抽象工厂,而无需关注具体的日志输出类型。
- 数据库连接池:根据不同的数据库类型(MySQL、Oracle、SQL Server等)提供不同的连接池工厂来创建相应的数据库连接对象。
- 图形界面框架:不同平台(Windows、Mac、Linux)上创建不同的UI组件,通过工厂方法返回适合该平台的组件。
工厂方法模式通过简单的接口和抽象化的工厂类实现了灵活的对象创建方式,尤其适用于系统需要扩展或更换产品类型的场景。
版权声明
- 本文内容属于原创,欢迎转载,但请务必注明出处和作者,尊重原创版权。
- 转载时,请附带原文链接并注明“本文作者:扣丁梦想家
- 禁止未经授权的商业转载。
如果您有任何问题或建议,欢迎留言讨论。