目录
- 背景/问题
- 解决方案
- 思路
- 方案
- 图解
- 简单工厂模式/静态工厂模式
- 工厂方法模式
- 代码示例:图形工厂
- 意图
- 主要解决
- 何时使用
- 如何解决
- 关键代码
- 工厂模式的优点
- 工厂模式的缺点
- 使用场景
- 注意事项
背景/问题
- 在软件设计中,我们经常遇到需要创建不同类型对象的情况。
- 但是,如果直接在代码中实例化对象,会使代码紧密耦合在一起,难以维护和扩展。
- 此外,如果对象的创建方式需要变化,那么就需要在整个代码中进行大量的修改。工厂方法模式旨在解决这个问题
解决方案
思路
- 工厂方法模式提供了一个创建对象的接口,但是将具体的对象创建延迟到子类中。
- 这样,客户端代码不需要知道要创建的具体对象的类,只需要通过工厂方法来创建对象。
- 这使得客户端代码与具体对象的创建解耦,提高了代码的灵活性和可维护性。
方案
- 在工厂方法模式中,通常会定义一个抽象工厂类,其中包含一个创建对象的抽象方法,而具体的对象创建则由具体的子类实现。
- 这样,每个具体的子类都可以根据需要创建不同类型的对象,而客户端代码只需要通过抽象工厂类来调用工厂方法,而不需要关心具体的对象创建细节。
图解
简单工厂模式/静态工厂模式
用来生产同一等级结构中的任意产品。(对于增加新的产品,需要修改已有代码)
工厂方法模式
用来生产同一等级结构中的固定产品。(支持增加任意产品)
代码示例:图形工厂
意图
定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。
主要解决
主要解决接口选择的问题。
何时使用
我们明确地计划不同条件下创建不同实例时。
如何解决
让其子类实现工厂接口,返回的也是一个抽象的产品。
关键代码
创建过程在其子类执行。
// 首先,我们需要定义一个图形接口
interface Shape {
void draw();
}
// 然后,我们实现两个具体的图形类,分别是 Circle(圆形)和 Rectangle(矩形)
class Circle implements Shape {
@Override
public void draw() {
System.out.println("Drawing a circle");
}
}
class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Drawing a rectangle");
}
}
// 接下来,我们创建一个抽象工厂类 ShapeFactory
// 它定义了一个抽象的工厂方法 createShape,子类将实现这个方法来创建具体的图形对象
abstract class ShapeFactory {
abstract Shape createShape();
}
// 然后,我们创建两个具体的工厂类,分别是 CircleFactory 和 RectangleFactory
// 它们分别实现了 ShapeFactory 并重写了 createShape 方法来返回相应的图形对象
class CircleFactory extends ShapeFactory {
@Override
Shape createShape() {
return new Circle();
}
}
class RectangleFactory extends ShapeFactory {
@Override
Shape createShape() {
return new Rectangle();
}
}
// 我们可以使用这些工厂类来创建图形对象
public class FactoryMethodExample {
public static void main(String[] args) {
ShapeFactory circleFactory = new CircleFactory();
Shape circle = circleFactory.createShape();
circle.draw();
ShapeFactory rectangleFactory = new RectangleFactory();
Shape rectangle = rectangleFactory.createShape();
rectangle.draw();
}
}
工厂模式的优点
- 松耦合: 客户端代码与具体对象的创建解耦,使得系统更具弹性和可维护性。
- 扩展性: 通过添加新的具体工厂和产品子类,可以很容易地扩展系统以支持新的对象类型。
- 封装性: 将对象的创建集中在工厂类中,封装了对象的创建细节,使得客户端代码更简洁。
简单工厂可以使客户端免除直接创建对象的职责,能够根据需要创建出对应的产品。实现客户端和产品类代码分离。此外可以通过配置文件来实现不修改客户端代码的情况下添加新的具体产品类(改进)
然而,工厂方法模式也可能引入一些额外的复杂性,因为需要定义多个工厂类和产品类的层次结构。这可能会导致系统中类的数量增加。在选择使用工厂方法模式时,需要根据具体情况进行权衡。
工厂方法模式在实际应用中非常常见,例如:图形库可以使用工厂方法模式来创建不同类型的图形对象,数据库访问框架可以使用工厂方法模式来创建不同类型的数据库连接等。
工厂模式的缺点
违背开闭原则,如果需要新增其他产品类,就必须在工厂类中新增if-else逻辑判断(可以通过配置文件来改进)。但是整体来说,系统扩展还是相对其他工厂模式要困难。
使用场景
- 日志记录器:记录可能记录到本地硬盘、系统事件、远程服务器等,用户可以选择记录日志到什么地方。
- 数据库访问,当用户不知道最后系统采用哪一类数据库,以及数据库可能有变化时。
注意事项
作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式。有一点需要注意的地方就是复杂对象适合使用工厂模式,而简单对象,特别是只需要通过 new 就可以完成创建的对象,无需使用工厂模式。如果使用工厂模式,就需要引入一个工厂类,会增加系统的复杂度。