ASP.NET Web API:用设计模式消除Controller中的If-Else分支
嘿,这个场景太适合用策略模式来重构了,既能摆脱那些缠人的if-else嵌套,还能让代码更易扩展和维护。另外咱们也可以用OOP的思路把RequestModel的行为封装起来,让控制器彻底和分支逻辑说拜拜。我给你一步步拆解:
1. 用策略模式替代If-Else:拆分业务逻辑
核心思路是把每种组合场景的业务逻辑封装成独立的策略类,然后通过一个“策略提供者”来匹配并执行对应逻辑。
第一步:定义策略接口
先给所有业务逻辑约定一个统一的接口:
public interface IInventoryStrategy { // 判断当前策略是否匹配请求场景 bool IsMatch(RequestModel model, int existingQty); // 执行对应业务逻辑 void Execute(RequestModel model, int existingQty); }
第二步:实现具体策略类
每种组合场景对应一个策略类,比如你提到的「现有库存小于请求数量且Owner为true」的场景:
public class OwnerTrueQtyLessStrategy : IInventoryStrategy { public bool IsMatch(RequestModel model, int existingQty) { return existingQty < model.Quantity && model.Owner == true; } public void Execute(RequestModel model, int existingQty) { // 这里写原来第一个if块里的业务逻辑 // 比如:更新库存、生成记录等 } }
再比如「现有库存等于请求数量」的场景:
public class QtyEqualStrategy : IInventoryStrategy { public bool IsMatch(RequestModel model, int existingQty) { return existingQty == model.Quantity; } public void Execute(RequestModel model, int existingQty) { // 对应的业务逻辑,不用处理DoSplit和Owner的判断 } }
你可以按照这个方式,把所有if-else分支都拆成独立的策略类。
第三步:创建策略提供者
这个类负责管理所有策略,在运行时找到匹配的策略:
public class InventoryStrategyProvider { private readonly IEnumerable<IInventoryStrategy> _strategies; // 借助ASP.NET Core的依赖注入,自动注入所有实现了IInventoryStrategy的类 public InventoryStrategyProvider(IEnumerable<IInventoryStrategy> strategies) { _strategies = strategies; } public IInventoryStrategy GetMatchingStrategy(RequestModel model, int existingQty) { // 找到第一个匹配的策略 var strategy = _strategies.FirstOrDefault(s => s.IsMatch(model, existingQty)); if (strategy == null) { // 可以抛出自定义异常,或者返回一个默认策略处理未知场景 throw new InvalidOperationException("No matching strategy found for the request"); } return strategy; } }
2. 优化RequestModel:用OOP封装判断逻辑
因为模型是从前端JS传过来的,我们可以给它加一些辅助方法,把分散的判断逻辑封装进去,让策略类的代码更简洁:
public class RequestModel { public string PartType { get; set; } public int Quantity { get; set; } public decimal UnitCost{ get; set; } public bool? Owner { get; set; } public bool? DoSplit { get; set; } // 假设你原来的代码里有SerialId,不然GetInitialQuantity没法用 public string SerialId { get; set; } // 封装判断逻辑,让代码更可读 public bool IsOwnerTrue() => Owner.HasValue && Owner.Value; public bool IsOwnerFalse() => Owner.HasValue && !Owner.Value; public bool IsQtyGreaterThanExisting(int existingQty) => Quantity > existingQty; public bool IsQtyEqualExisting(int existingQty) => Quantity == existingQty; // 可以根据需求添加更多类似的封装方法 }
这样策略类的IsMatch方法就可以写成更清晰的形式:
public bool IsMatch(RequestModel model, int existingQty) { return model.IsQtyGreaterThanExisting(existingQty) && model.IsOwnerTrue(); }
3. 控制器彻底消除分支
现在你的Post方法就变得超级干净,不需要任何if-else:
[HttpPost] public IActionResult ProcessInventory([FromBody] RequestModel model) { int existingQty = GetInitialQuantity(model.SerialId); // 找到匹配的策略并执行 var strategy = _strategyProvider.GetMatchingStrategy(model, existingQty); strategy.Execute(model, existingQty); return Ok(); }
额外优化:处理默认场景
为了避免出现找不到策略的情况,你可以加一个默认策略,处理所有未被覆盖的场景:
public class DefaultInventoryStrategy : IInventoryStrategy { public bool IsMatch(RequestModel model, int existingQty) { return true; // 匹配所有未被其他策略处理的情况 } public void Execute(RequestModel model, int existingQty) { // 比如记录日志、返回友好错误提示等 } }
只要确保默认策略在所有策略中最后被匹配(比如注册DI时放在最后,或者给策略加优先级排序),就能兜底处理未知情况。
为什么这么做?
- 可扩展性:以后新增组合逻辑,只需要加一个新的策略类,完全不用修改原有代码,符合开放封闭原则
- 可维护性:每个策略类只处理一种场景,逻辑清晰,调试和修改都很方便
- 解耦:控制器只负责接收请求、获取数据、调用策略,不处理具体业务逻辑,符合单一职责原则
内容的提问来源于stack exchange,提问作者Bharathg
相关产品推荐
相关产品推荐

