工厂方法模式和抽象工厂模式详解

由于工厂方法模式和抽象工厂模式有点类似,可以放着一块说下。

一、工厂方法模式 (Factory Method Pattern)

场景描述

假设需要实现一个跨平台日志系统,支持文件日志和数据库日志,且未来可能扩展其他日志方式。通过工厂方法模式,将日志对象的创建延迟到子类,避免修改核心代码。

java 复制代码
// 抽象产品:日志接口
interface Logger {
    void log(String message);
}

// 具体产品1:文件日志
class FileLogger implements Logger {
    @Override
    public void log(String message) {
        System.out.println("文件日志记录: " + message);
    }
}

// 具体产品2:数据库日志
class DatabaseLogger implements Logger {
    @Override
    public void log(String message) {
        System.out.println("数据库日志记录: " + message);
    }
}

// 抽象工厂:定义创建日志的接口
abstract class LoggerFactory {
    // 工厂方法(由子类实现具体创建逻辑)
    public abstract Logger createLogger();

    // 公共业务逻辑(如日志预处理)
    public void log(String message) {
        Logger logger = createLogger();
        logger.log("[预处理] " + message);
    }
}

// 具体工厂1:文件日志工厂
class FileLoggerFactory extends LoggerFactory {
    @Override
    public Logger createLogger() {
        return new FileLogger();
    }
}

// 具体工厂2:数据库日志工厂
class DatabaseLoggerFactory extends LoggerFactory {
    @Override
    public Logger createLogger() {
        return new DatabaseLogger();
    }
}

// 测试代码
public class FactoryMethodDemo {
    public static void main(String[] args) {
        // 使用文件日志
        LoggerFactory fileFactory = new FileLoggerFactory();
        fileFactory.log("用户登录成功");

        // 使用数据库日志
        LoggerFactory dbFactory = new DatabaseLoggerFactory();
        dbFactory.log("订单创建完成");
    }
}

二、抽象工厂模式 (Abstract Factory Pattern)

场景描述

开发一个跨平台UI库,需要为Windows和macOS创建风格一致的按钮和文本框,并确保同一家族的产品兼容。

java 复制代码
// 抽象产品族:按钮
interface Button {
    void render();
}

// 抽象产品族:文本框
interface TextBox {
    void input(String text);
}

// 具体产品:Windows按钮
class WindowsButton implements Button {
    @Override
    public void render() {
        System.out.println("Windows风格按钮渲染");
    }
}

// 具体产品:Windows文本框
class WindowsTextBox implements TextBox {
    @Override
    public void input(String text) {
        System.out.println("Windows文本框输入: " + text);
    }
}

// 具体产品:macOS按钮
class MacOSButton implements Button {
    @Override
    public void render() {
        System.out.println("macOS风格按钮渲染");
    }
}

// 具体产品:macOS文本框
class MacOSTextBox implements TextBox {
    @Override
    public void input(String text) {
        System.out.println("macOS文本框输入: " + text);
    }
}

// 抽象工厂:定义创建产品族的方法
interface GUIFactory {
    Button createButton();
    TextBox createTextBox();
}

// 具体工厂1:Windows工厂
class WindowsFactory implements GUIFactory {
    @Override
    public Button createButton() {
        return new WindowsButton();
    }

    @Override
    public TextBox createTextBox() {
        return new WindowsTextBox();
    }
}

// 具体工厂2:macOS工厂
class MacOSFactory implements GUIFactory {
    @Override
    public Button createButton() {
        return new MacOSButton();
    }

    @Override
    public TextBox createTextBox() {
        return new MacOSTextBox();
    }
}

// 客户端代码
class Application {
    private Button button;
    private TextBox textBox;

    public Application(GUIFactory factory) {
        button = factory.createButton();
        textBox = factory.createTextBox();
    }

    public void run() {
        button.render();
        textBox.input("Hello World");
    }
}

// 测试代码
public class AbstractFactoryDemo {
    public static void main(String[] args) {
        // 创建Windows风格应用
        Application winApp = new Application(new WindowsFactory());
        winApp.run();

        // 创建macOS风格应用
        Application macApp = new Application(new MacOSFactory());
        macApp.run();
    }
}

两种模式对比

特性 工厂方法模式 抽象工厂模式
核心目的 创建单一产品 创建多个相关产品的家族
扩展维度 纵向扩展(新增产品类型) 横向扩展(新增产品族)
接口复杂度 一个工厂方法 多个工厂方法
典型应用场景 日志系统、数据库连接池 跨平台UI、主题换肤、游戏皮肤
代码改动范围 添加新工厂类 添加新工厂类和产品家族

真实场景问题解决

工厂方法模式应用痛点

问题:需要支持多种日志存储方式,但不想让客户端依赖具体实现类

解决:通过工厂类隔离具体实现,客户端只依赖抽象接口

抽象工厂模式应用痛点

问题:需要保证Windows按钮必须与Windows文本框搭配使用

解决:通过同一工厂类创建所有关联组件,避免风格不一致

扩展性挑战

新增日志类型:只需添加XXXLoggerFactory,无需修改现有代码

新增操作系统支持:添加LinuxFactory及相关产品类即可

代码设计亮点

工厂方法模式

符合开闭原则:新增日志类型只需扩展工厂类

客户端代码与具体产品解耦

抽象工厂模式

保证产品族一致性:同一工厂创建的所有组件风格统一

切换产品族只需更换工厂实例(如从Windows切换到macOS)

一句话总结

工厂方法模式:解决"如何创建一个 对象"的问题,通过子类决定具体类型。

抽象工厂模式:解决"如何创建一组 相关对象"的问题,通过工厂组合保证兼容性。

这两种模式还是很相似的,感觉不就用太纠结。抽象工厂模式可以通过组合的方式拓展产品,但是更为复杂,如果只需要简单地生产单个对象,只需要工厂方法模式就足够了,需要提前评估好拓展性。

相关推荐
code2cat8 分钟前
【随笔】RAG语义缓存:问题很相似,答案就能直接复用吗
java·缓存·知识库·rag
Rain的Java大神之路30 分钟前
面了 50 个候选人,90% 都挂在 LeetCode 3 无重复字符的最长子串:滑动窗口的 5 个致命坑
java·后端·leetcode
西凉的悲伤31 分钟前
Jsoup 库 HTML 解析详解
java·前端·html·jsoup
十碗饭吃不饱43 分钟前
Apache POI 踩坑:setFontFamily 二次设置字体不生效、样式残留问题深度解析
java·word·apache
我命由我123451 小时前
6-2.Python 异常处理 - 异常捕获(捕获指定异常、常见异常类型、异常信息)
java·运维·开发语言·python·http·https·java-ee
zaizai10071 小时前
STL深度剖析2
java·c++·算法
周厉1 小时前
WebSocket 使用场景与实现方法:Java + Vue3 全栈实战
java·websocket·vue3·websocket双向通讯
wdfk_prog1 小时前
lwip教程 38:从 `lwipopts.h` 到 Port Contract——lwIP 裁剪、构建选择、OS Port 与 Network Port
java·开发语言
吹什么轩1 小时前
MySQL 内置函数全景:日期 / 字符串 / 数学 / 其他,一次讲透(附索引杀手排查)
java·数据库·面试
略略略咯咯1 小时前
12333
java