抽象工厂模式 Abastract Factory Pattern

发布于:2025-07-31 ⋅ 阅读:(23) ⋅ 点赞:(0)

基本内容

定义一个抽象工厂接口来创建一系列相关或依赖对象的家族,而无需指定它们具体的类。其核心思想是将对象的创建与使用解耦,允许客户端通过抽象接口来获取一组相关的对象,而无需关心这些对象的具体实现。

回顾工厂方法模式

在工厂方法模式中,示例如下:

// 产品接口
public interface Logger {
    void log(String message);
}

// 产品实现
public class ConsoleLogger implements Logger {
    public void log(String message) {
        System.out.println("控制台日志: " + message);
    }
}

public class FileLogger implements Logger {
    public void log(String message) {
        System.out.println("文件日志: " + message);
    }
}

// 抽象工厂
public interface LoggerFactory {
    Logger createLogger();
}

// 具体工厂
public class ConsoleLoggerFactory implements LoggerFactory {
    public Logger createLogger() {
        return new ConsoleLogger();
    }
}

public class FileLoggerFactory implements LoggerFactory {
    public Logger createLogger() {
        return new FileLogger();
    }
}

// 使用
LoggerFactory factory = new ConsoleLoggerFactory();
Logger logger = factory.createLogger();
logger.log("Hello");


这里定义了一个抽象接口,基于该抽象接口实现了一系列具体类,那么这些具体类可以看作是同一类产品。在抽象工厂中,我们也实现了一个对象构造方法,返回的是一类产品,然后我们使用具体工厂实现了抽象工厂的创建方法,每个工厂创建其对应实现类的对象。
总结下:工厂方法模式每个工厂只创建一种产品,而产品归根到底是同一类的,工厂创建产品的方法也是同一种方法的重写。

下面我们考虑:如果有多种相关类别的产品,由此我们引入产品族:

产品族

产品族是指由同一工厂创建的一组产品,这些产品在设计上相互配合,共同完成某个功能或满足某个场景的需求。
我们使用常见的家用电器举例:
在这里插入图片描述
上图中的正方形代表洗衣机,圆形代表空调,菱形代表热水器。我们用一个矩形将他们框起来,构成一个产品族,假设这个产品族是美的生产的。这个美的就是一个具体工厂,生产了一个产品族的产品。
在这里插入图片描述
我们还知道,除了美的,当然还有其他厂家,比如小米,格力,海信。于是左侧的工厂生产他对应的那一行产品族,即每个具体工厂都生产其对应的洗衣机,空调,热水器。这些产品共同构建一个现代化家庭的常用电器。

示例

回到logger示例中,现在我们有一个产品族,其构成是:logger产品和loggerFormat产品,一个是写入日志的,一个是定义日志格式的。他们配置实现用什么格式写入日志

// 抽象产品1:日志记录器
public interface Logger {
    void log(String message);
}

// 抽象产品2:日志格式化器
public interface LoggerFormatter {
    String format(String message);
}
// 简洁风格的Logger
public class SimpleLogger implements Logger {
    public void log(String message) {
        System.out.println("简洁日志: " + message);
    }
}

// 简洁风格的Formatter
public class SimpleFormatter implements LoggerFormatter {
    public String format(String message) {
        return "[" + message + "]";
    }
}

// 详细风格的Logger
public class DetailedLogger implements Logger {
    public void log(String message) {
        System.out.println("详细日志: [时间] " + message);
    }
}

// 详细风格的Formatter
public class DetailedFormatter implements LoggerFormatter {
    public String format(String message) {
        return "详细格式: " + message + " (时间戳)";
    }
}

现在我们创建的抽象工厂,显然不是和之前一样定义一个抽象获取对象的方法就行了,而是需要两个

public interface LoggerFactory {
    Logger createLogger();          // 创建日志记录器
    LoggerFormatter createFormatter(); // 创建日志格式化器
}

然后我们实现具体的工厂,

// 简洁风格工厂
public class SimpleLoggerFactory implements LoggerFactory {
    public Logger createLogger() {
        return new SimpleLogger();
    }
    public LoggerFormatter createFormatter() {
        return new SimpleFormatter();
    }
}

// 详细风格工厂
public class DetailedLoggerFactory implements LoggerFactory {
    public Logger createLogger() {
        return new DetailedLogger();
    }
    public LoggerFormatter createFormatter() {
        return new DetailedFormatter();
    }
}

客户端使用的时候不需要关注对象创建的过程:

public class Client {
    public static void main(String[] args) {
        // 使用简洁风格工厂
        LoggerFactory simpleFactory = new SimpleLoggerFactory();
        Logger simpleLogger = simpleFactory.createLogger();
        LoggerFormatter simpleFormatter = simpleFactory.createFormatter();

        simpleLogger.log(simpleFormatter.format("Hello")); 
        // 输出: 简洁日志: [Hello]

        // 使用详细风格工厂
        LoggerFactory detailedFactory = new DetailedLoggerFactory();
        Logger detailedLogger = detailedFactory.createLogger();
        LoggerFormatter detailedFormatter = detailedFactory.createFormatter();

        detailedLogger.log(detailedFormatter.format("Hello"));
        // 输出: 详细日志: [时间] 详细格式: Hello (时间戳)
    }
}

总结

抽象工厂模式 = 多个工厂方法 + 产品族约束。
如果你的系统需要同时创建一组相关对象(如UI组件、日志系统、数据库连接池等),抽象工厂模式是更合适的选择。

问题

如果我们继续扩展产品族,例如,在家具里面新增电风扇,那么我们的抽象工厂到具体工厂都需要调整,显然这违背了开闭原则,由此我们知道抽象工厂模式也是有缺点的。即:
1.扩展困难,需要修改很多地方
2.增加了系统的抽象性和理解难度
不过在实际应用中,一方面如果我们确定了产品族内容,则可以考虑,另一方面,产品升级是正常的,不应该有洁癖或者完美主义的情节。只要不频繁升级,也可以根据实际情况考虑不遵循开闭原则。


网站公告

今日签到

点亮在社区的每一天
去签到