工厂设计模式是 Java 中常用的创建型设计模式,核心思想是将对象的创建逻辑与使用逻辑解耦,让代码更灵活、可维护。它分为三种类型:
一、简单工厂模式(Simple Factory)
- 作用:通过一个工厂类,根据输入参数动态创建不同类型的对象。
- 适用场景:对象类型较少且创建逻辑简单时。
- 示例:
public class ShapeFactory { public Shape createShape(String type) { if ("circle".equals(type)) return new Circle(); if ("rectangle".equals(type)) return new Rectangle(); return null; } } // 调用 Shape circle = new ShapeFactory().createShape("circle");
二、工厂方法模式(Factory Method)
- 作用:定义一个创建对象的接口,由子类决定具体实例化的类。
- 特点:每个产品对应一个工厂类,符合“开闭原则”(扩展时不修改原有代码)。
- 示例:
interface ShapeFactory { Shape createShape(); } class CircleFactory implements ShapeFactory { public Shape createShape() { return new Circle(); } } // 调用 Shape circle = new CircleFactory().createShape();
三、抽象工厂模式(Abstract Factory)
- 作用:创建一组相关或依赖的复杂对象(产品族),例如不同操作系统的 UI 组件。
- 特点:一个工厂接口对应多个产品创建方法。
- 示例:
interface GUIFactory { Button createButton(); Window createWindow(); } class WindowsFactory implements GUIFactory { public Button createButton() { return new WinButton(); } public Window createWindow() { return new WinWindow(); } }
核心优势
- 解耦:分离对象创建和业务逻辑。
- 扩展性:新增产品时只需扩展工厂类。
- 统一管理:集中控制对象的创建逻辑(例如配置、缓存)。
典型应用场景
- 对象创建过程复杂(如依赖配置、数据库连接)。
- 需要统一管理不同类的实例化(如日志记录器、数据库驱动)。
- 系统需要支持多种产品变体(如不同主题的 UI 组件)。
通过工厂模式,代码会更清晰,且更容易应对需求变化。
工厂方法模式可以返回接口返回类型的子类吗
是的,工厂方法模式可以返回接口(或抽象类)的“子类型”(即实现类或子类)。这是工厂方法模式的核心设计思想之一,也是多态(Polymorphism)和里氏替换原则(LSP)的直接体现。以下是详细解释:
关键点说明
-
返回类型是接口(或抽象类)
工厂方法模式中,工厂方法的返回类型通常是一个接口或抽象类(例如Shape
),而不是具体类。 -
具体工厂返回实现类
每个具体工厂子类(例如CircleFactory
)会实现工厂方法,返回该接口的具体实现类(例如Circle
),而Circle
是Shape
接口的实现类。 -
多态特性
通过接口类型接收返回值,调用方无需关心具体实现类,直接通过接口方法操作对象,实现解耦。
示例代码
1. 定义接口和实现类
// 接口(或抽象类)
interface Shape {
void draw();
}
// 接口的实现类("子类型")
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");
}
}
2. 定义工厂接口和具体工厂
// 工厂接口
interface ShapeFactory {
Shape createShape(); // 返回类型是接口
}
// 具体工厂返回 Circle(Shape 的实现类)
class CircleFactory implements ShapeFactory {
@Override
public Shape createShape() {
return new Circle(); // 返回接口的子类型(实现类)
}
}
// 具体工厂返回 Rectangle
class RectangleFactory implements ShapeFactory {
@Override
public Shape createShape() {
return new Rectangle(); // 返回接口的子类型(实现类)
}
}
3. 调用示例
public class Client {
public static void main(String[] args) {
ShapeFactory factory = new CircleFactory();
Shape shape = factory.createShape(); // 实际类型是 Circle,但以接口 Shape 接收
shape.draw(); // 输出 "Drawing a circle"
}
}
为什么这是合法的?
-
多态的支持
Java 允许将子类(或实现类)对象赋值给父类(或接口)类型的引用。例如:Shape shape = new Circle(); // 完全合法
-
里氏替换原则(LSP)
所有子类(或实现类)必须能够替换它们的父类(或接口)。工厂方法返回的子类对象完全满足接口的行为约定。
核心优势
- 解耦调用方与具体类:调用方只需依赖接口,无需知道具体实现类。
- 灵活扩展:新增实现类时,只需添加对应的工厂类,无需修改现有代码。
- 符合开闭原则:对扩展开放,对修改关闭。
总结
工厂方法模式通过返回接口的子类型(实现类),实现了:
- 对象创建逻辑的封装。
- 调用方与具体类的解耦。
- 系统的高扩展性和维护性。
这种设计是 Java 多态特性的典型应用,也是面向接口编程的最佳实践之一。
灵活扩展:新增实现类时,只需添加对应的工厂类,无需修改现有代码。这是啥意思,举个简单例子
好的!我们通过一个具体例子来理解这句话的含义。假设你已经有一个基于工厂方法模式的形状绘制系统,现在需要新增一种形状(例如 Triangle
),而整个过程不需要修改任何已有代码,只需添加新类即可。
原始代码结构(未扩展前)
1. 定义接口和现有实现类
// 形状接口
interface Shape {
void draw();
}
// 现有实现类:圆形
class Circle implements Shape {
@Override
public void draw() {
System.out.println("画一个圆形");
}
}
// 现有实现类:矩形
class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("画一个矩形");
}
}
2. 定义工厂接口和现有工厂
// 工厂接口
interface ShapeFactory {
Shape createShape();
}
// 圆形工厂
class CircleFactory implements ShapeFactory {
@Override
public Shape createShape() {
return new Circle(); // 返回 Circle 对象
}
}
// 矩形工厂
class RectangleFactory implements ShapeFactory {
@Override
public Shape createShape() {
return new Rectangle(); // 返回 Rectangle 对象
}
}
3. 客户端调用
public class Client {
public static void main(String[] args) {
// 使用圆形工厂
ShapeFactory factory = new CircleFactory();
Shape shape = factory.createShape();
shape.draw(); // 输出 "画一个圆形"
// 使用矩形工厂
factory = new RectangleFactory();
shape = factory.createShape();
shape.draw(); // 输出 "画一个矩形"
}
}
需求变更:新增三角形
现在需要支持绘制三角形(Triangle
),但不能修改原有代码(避免影响已有功能)。
扩展步骤(仅添加新代码)
1. 添加新的形状实现类
// 新增三角形实现类
class Triangle implements Shape {
@Override
public void draw() {
System.out.println("画一个三角形");
}
}
2. 添加对应的工厂类
// 新增三角形工厂
class TriangleFactory implements ShapeFactory {
@Override
public Shape createShape() {
return new Triangle(); // 返回 Triangle 对象
}
}
客户端使用新功能
客户端只需使用新的 TriangleFactory
,无需修改原有代码:
public class Client {
public static void main(String[] args) {
// 使用新增的三角形工厂
ShapeFactory factory = new TriangleFactory(); // 仅需修改这一行!
Shape shape = factory.createShape();
shape.draw(); // 输出 "画一个三角形"
}
}
关键点
-
原有代码未修改
- 没有改动
Shape
接口、Circle
、Rectangle
、CircleFactory
、RectangleFactory
和原有客户端代码。 - 完全符合开闭原则(对扩展开放,对修改关闭)。
- 没有改动
-
扩展只需添加新类
- 新增
Triangle
和TriangleFactory
两个类,系统即支持三角形绘制。
- 新增
-
客户端灵活切换
- 客户端只需决定使用哪个工厂(如
new TriangleFactory()
),即可获得对应的形状对象。
- 客户端只需决定使用哪个工厂(如
实际开发中的优势
- 降低风险:不修改旧代码,避免引入意外错误。
- 维护性高:新增功能时,原有逻辑保持稳定。
- 团队协作:不同开发者可以并行开发新功能,只需约定接口即可。
总结
工厂方法模式的“灵活扩展”体现在:新增功能时,只需扩展新类(实现类+工厂类),无需触碰已有代码。这种设计让系统像搭积木一样可扩展,非常适合需求频繁变动的场景。