You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SOLID原则:单一职责原则与开闭原则是否互斥?

如何同时遵循单一职责原则(SRP)与开闭原则(OCP)

很多开发者会觉得这两个原则看起来有点矛盾——SRP要求类只专注一件事,OCP要求不能修改原有代码却要能扩展功能。但其实它们是互补的:SRP帮你把系统拆成小而清晰的单一职责模块,OCP则帮你在这些模块之间搭建灵活的扩展机制,避免硬编码带来的耦合问题。

核心思路:把「变更理由」和「扩展点」解耦

SRP说的「一个变更理由」,不是指类永远不能有任何变动,而是它只对一种类型的变化负责。比如一个订单处理类,它的职责是执行订单的业务逻辑,那么「订单业务规则调整」是它唯一的变更理由;如果要新增支付方式,这绝对不该成为修改订单类的理由——这时候就该用OCP,把支付方式设计成可扩展的独立组件,让订单类依赖支付抽象而非具体实现。

用工厂模式的例子解决冲突

你提到工厂模式可能违反OCP,比如传统的简单工厂:

public class ProductFactory {
    public Product createProduct(String type) {
        if (type.equals("A")) {
            return new ProductA();
        } else if (type.equals("B")) {
            return new ProductB();
        }
        // 新增ProductC时,必须修改这里的代码!
        throw new IllegalArgumentException("Unknown product type");
    }
}

这个工厂类确实违反了OCP(新增产品必须改代码),同时也违反了SRP——它的职责是「创建所有产品」,变更理由会有N种(新增A、修改B的创建逻辑、删除C…)。那怎么改造?

1. 先按SRP拆分:每个产品对应一个专属工厂

把原来的单一工厂拆成多个具体工厂类,每个只负责创建一种产品:

// 抽象工厂接口,定义创建产品的标准
public interface ProductFactory {
    Product createProduct();
}

// 只负责创建ProductA的工厂,职责单一
public class ProductAFactory implements ProductFactory {
    @Override
    public Product createProduct() {
        return new ProductA();
    }
}

// 只负责创建ProductB的工厂,职责单一
public class ProductBFactory implements ProductFactory {
    @Override
    public Product createProduct() {
        return new ProductB();
    }
}

现在每个具体工厂都符合SRP:它们只有一个变更理由——对应产品的创建逻辑变化。比如修改ProductA的构造参数,只需要改ProductAFactory,其他工厂完全不受影响。

2. 用注册机制实现OCP

现在问题来了:怎么根据类型快速找到对应的工厂?这时候可以加一个工厂注册器,它的职责只有一个:管理所有具体工厂的注册与查找,符合SRP:

public class FactoryRegistry {
    private static final Map<String, ProductFactory> factories = new HashMap<>();

    // 初始化已知工厂(也可以用配置文件、注解扫描等方式)
    static {
        factories.put("A", new ProductAFactory());
        factories.put("B", new ProductBFactory());
    }

    // 提供外部注册入口,允许新增工厂
    public static void registerFactory(String type, ProductFactory factory) {
        factories.put(type, factory);
    }

    // 根据类型获取对应工厂
    public static ProductFactory getFactory(String type) {
        ProductFactory factory = factories.get(type);
        if (factory == null) {
            throw new IllegalArgumentException("Unknown product type");
        }
        return factory;
    }
}

现在新增ProductC的时候,只需要做三件事:

  • 编写ProductC类
  • 编写ProductCFactory实现ProductFactory接口
  • 调用FactoryRegistry.registerFactory("C", new ProductCFactory())

完全不需要修改原有任何代码——完美符合OCP!

通用实践方法总结

  • 先做SRP拆分:把大职责拆成小的、单一的模块,每个模块只对一种变化负责。
  • 依赖抽象而非具体实现:这是OCP的核心,让模块之间通过接口/抽象类交互,避免直接绑定具体类。
  • 用扩展点代替修改:把可能变化的部分做成可插拔组件,比如注册器、策略模式、装饰器模式等,新增功能只需要添加新组件,不用动原有代码。

记住:SRP帮你避免「牵一发而动全身」,OCP帮你在不破坏原有代码的前提下扩展功能——两者结合,就能打造出既清晰又灵活的系统。

内容的提问来源于stack exchange,提问作者Matthew Layton

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 08:27:52