如何践行单一职责原则?三种实现方式及DI与接口的作用
单一职责原则(SRP)实现方案分析与DI/接口的角色
三种实现方式的对比与最佳选择
我们逐个分析你给出的三种实现方式:
1. 静态方法(Approach2)
- 优势:实现极简,不需要实例化对象,适合无状态的纯逻辑场景(比如你这个固定乘10的计算),调用成本低。
- 劣势:扩展性差,无法通过依赖注入替换逻辑;测试时难以模拟,只能硬编码逻辑;如果后续需要给计算逻辑加状态(比如缓存计算结果),完全无法适配。
2. 实例化类(Approach1)
- 优势:符合面向对象封装思想,类可以持有状态(当前例子没用到,但后续扩展可用);支持依赖注入,方便测试和扩展(比如继承该类修改计算逻辑);职责单一,
SingleResponsabiltyApproach1只负责乘10的计算,和Factoriser完全解耦。 - 劣势:每次使用需要实例化对象,但C#中这种轻量对象的实例化开销几乎可以忽略,完全不用纠结。
3. 传递完整父类(Approach3)
- 核心问题:严重违反单一职责原则,
SingleResponsabiltyApproach3直接依赖Factoriser的完整实例,导致两个类耦合度极高——Factoriser的任何字段修改、逻辑变更都可能影响这个类,完全违背了拆分臃肿类、降低耦合的初衷。 - 内存疑问:在C#中,引用类型参数传递的是引用(指针),不会复制整个对象,内存开销极小,但这不是重点,重点是这种设计的耦合问题必须避免。
最佳选择:如果当前场景只是简单的无状态计算,静态方法可以用,但从长期扩展性和代码可维护性考虑,实例化类(Approach1)是最优方案。绝对要避免Approach3的写法。
依赖注入(DI)与接口的角色
接口的作用
接口是落地SRP和开闭原则的核心工具:
- 定义抽象契约:比如定义
IFactorCalculator接口,约定Calculate(int value)方法,让计算类实现这个接口。这样Factoriser只依赖抽象接口,不依赖具体的计算实现。 - 解耦依赖:当需要修改计算逻辑(比如改成乘20),只需要新增一个实现
IFactorCalculator的类,不需要修改Factoriser的代码,完全符合“对扩展开放,对修改关闭”的原则。
依赖注入(DI)的作用
- 消除硬编码实例化:
Factoriser不需要自己new计算类实例,而是通过构造函数或方法参数接收IFactorCalculator的实例,由外部(比如DI容器)负责创建和注入。 - 提升可测试性:测试时可以注入一个模拟的
IFactorCalculator实现,验证Factoriser的逻辑是否正确,不需要依赖真实的计算逻辑。 - 增强灵活性:可以根据不同场景切换计算实现(比如生产环境用普通计算,测试环境用模拟计算)。
优化后的代码示例
namespace SingleResponsabilityTest { // 定义抽象接口,约定计算契约 internal interface IFactorCalculator { int Calculate(int value); } // 具体计算类,只负责乘10的逻辑,符合SRP internal class TenFactorCalculator : IFactorCalculator { public int Calculate(int value) { return value * 10; } } // Factoriser只负责业务逻辑,依赖抽象接口,不耦合具体实现 internal class Factoriser { private readonly IFactorCalculator _calculator; public int classSpecificInt = 10; // 构造函数注入依赖 public Factoriser(IFactorCalculator calculator) { _calculator = calculator; } public void DoFactorTen() { Console.WriteLine(_calculator.Calculate(classSpecificInt)); Console.ReadLine(); } } internal class Program { static void Main(string[] args) { // 实际项目中可由DI容器管理实例,这里手动示例 IFactorCalculator calculator = new TenFactorCalculator(); Factoriser factoriser = new Factoriser(calculator); factoriser.DoFactorTen(); } } }
内容的提问来源于stack exchange,提问作者stigzler
相关产品推荐
相关产品推荐

