违反SOLID原则的C# Calculator类重构方案咨询
代码问题判定
你判断的没错,这段代码首先违反单一职责原则,同时还违反了开闭原则、依赖倒置原则,存在硬编码字符串易出错、可扩展性差的问题:
- 单一职责违反点:
Calculator类同时承担了运算逻辑实现、运算类型匹配分发两个职责,加减乘除任意一个运算规则修改,都需要改动整个Calculator类的代码,很容易引入牵连bug - 开闭原则违反点:新增运算(比如取模、幂运算)必须修改
Calculate方法的if-else分支,侵入已稳定的原有代码 - 健壮性缺陷:硬编码字符串做分支判断很容易出现拼写错误,比如你贴的代码里除法的标识写的是
"devide"(正确拼写为divide),会直接导致除法调用失败;也没有做除数为0的校验、不支持运算的异常提示
重构方案
核心思路是抽象运算公共契约,拆分每个运算为独立实现类,让计算器类仅依赖抽象做请求分发,完全贴合SOLID要求:
- 首先定义运算的抽象接口,统一所有运算的行为规范
- 把加减乘除每种运算拆成独立的类,每个类只实现自己对应的运算逻辑
- 重构计算器类,依赖抽象接口完成运算注册和分发,不再耦合具体运算逻辑
重构后代码实现
/// <summary> /// 运算抽象契约,所有可支持的运算都需实现该接口 /// </summary> public interface IOperation { /// <summary> /// 运算类型唯一标识 /// </summary> string OperationCode { get; } /// <summary> /// 执行具体运算逻辑 /// </summary> int Calculate(int a, int b); } // 加法实现 public class AddOperation : IOperation { public string OperationCode => "add"; public int Calculate(int a, int b) => a + b; } // 减法实现 public class SubtractOperation : IOperation { public string OperationCode => "subtract"; public int Calculate(int a, int b) => a - b; } // 乘法实现 public class MultiplyOperation : IOperation { public string OperationCode => "multiply"; public int Calculate(int a, int b) => a * b; } // 除法实现(修正原代码拼写问题,增加参数合法性校验) public class DivideOperation : IOperation { public string OperationCode => "divide"; public int Calculate(int a, int b) { if (b == 0) throw new DivideByZeroException("除数不能为0"); return a / b; } } /// <summary> /// 重构后的计算器类 /// </summary> public class Calculator { private readonly Dictionary<string, IOperation> _operationMap; /// <summary> /// 构造函数注入所有需要支持的运算实例 /// </summary> /// <param name="operations">所有支持的运算实现集合</param> public Calculator(IEnumerable<IOperation> operations) { // 初始化时构建运算标识和实例的映射关系,忽略大小写匹配 _operationMap = operations.ToDictionary( op => op.OperationCode, StringComparer.OrdinalIgnoreCase); } public int Calculate(int a, int b, string operation) { if (!_operationMap.TryGetValue(operation, out var targetOperation)) { throw new NotSupportedException($"不支持的运算类型:{operation}"); } return targetOperation.Calculate(a, b); } }
调用示例
// 初始化计算器,注入需要支持的运算 var calculator = new Calculator(new List<IOperation> { new AddOperation(), new SubtractOperation(), new MultiplyOperation(), new DivideOperation() }); // 执行计算 int sum = calculator.Calculate(3, 5, "add"); // 返回8 int product = calculator.Calculate(4, 6, "multiply"); // 返回24 int quotient = calculator.Calculate(10, 2, "divide"); // 返回5
重构后对SOLID的符合说明
- 单一职责原则:每个具体运算类只负责自身的运算逻辑实现,
Calculator类仅负责运算注册、请求匹配分发,不同职责完全拆分,修改某一个运算逻辑不会影响其他模块 - 开闭原则:后续新增运算类型时,只需要新增一个实现
IOperation接口的类,初始化计算器时注入即可,完全不需要修改Calculator类的原有代码,对扩展开放、对修改关闭 - 里氏替换原则:所有
IOperation的实现类都可以互相替换,不会导致计算器运行异常 - 接口隔离原则:
IOperation接口仅定义运算必需的两个成员,没有冗余方法,所有实现类不需要依赖自己不需要的接口定义 - 依赖倒置原则:计算器类依赖抽象的
IOperation接口,不依赖加减乘除的具体实现,高层模块和低层模块都基于抽象耦合
内容的提问来源于stack exchange,提问作者Jafar ashrafi
相关产品推荐
相关产品推荐

