在写业务代码时,可能出现多层 if / else ,通常意味着以下问题之一或并存:
1.分支条件复杂、可读性差
2.业务规则易变、修改成本高
3.单一方法承担过多职责
卫语句、策略模式、状态模式正是针对不同"分支复杂性来源"而采用的三种典型重构手段。
一.卫语句
1.适用场景
"不满足条件就立即返回 / 抛异常"
适合用于:参数校验,前置条件校验,明显的异常路径,早退出逻辑
典型特征:if 之间没有状态变化,只是为了过滤非法情况,分支不代表不同业务策略
2.原始代码
csharp
public decimal CalculatePrice(Order order)
{
if (order != null)
{
if (order.Items != null && order.Items.Count > 0)
{
if (!order.IsCanceled)
{
return order.Items.Sum(x => x.Price);
}
}
}
return 0;
}
3.卫语句重构
csharp
public decimal CalculatePrice(Order order)
{
if (order == null) return 0;
if (order.Items == null || order.Items.Count == 0) return 0;
if (order.IsCanceled) return 0;
return order.Items.Sum(x => x.Price);
}
4.优缺点
- 极低改造成本
- 可读性显著提升
- 非常适合方法开头
- 不能解决真正的业务分支爆炸
- 不适合"不同规则 / 不同行为"的分支
二、策略模式(Strategy Pattern)
- 适用场景
"同一件事,不同算法 / 不同规则"
判断标准:if / else 中每个分支:都是在"做同一件事",但实现逻辑不同,业务规则未来可能扩展
典型示例:价格计算,折扣规则,运费计算,权限校验规则
- 原始 if / else 示例
csharp
public decimal CalculateDiscount(Order order)
{
if (order.CustomerType == CustomerType.Vip)
return order.Total * 0.8m;
else if (order.CustomerType == CustomerType.Normal)
return order.Total * 0.9m;
else if (order.CustomerType == CustomerType.New)
return order.Total;
else
return order.Total;
}
- 使用策略模式
csharp
//① 抽象策略接口
public interface IDiscountStrategy
{
decimal Calculate(Order order);
}
//② 具体策略实现
public class VipDiscountStrategy : IDiscountStrategy
{
public decimal Calculate(Order order) => order.Total * 0.8m;
}
public class NormalDiscountStrategy : IDiscountStrategy
{
public decimal Calculate(Order order) => order.Total * 0.9m;
}
public class NewCustomerDiscountStrategy : IDiscountStrategy
{
public decimal Calculate(Order order) => order.Total;
}
//③ 策略选择(替代 if / else)
public class DiscountStrategyFactory
{
private static readonly Dictionary<CustomerType, IDiscountStrategy> _strategies =
new()
{
{ CustomerType.Vip, new VipDiscountStrategy() },
{ CustomerType.Normal, new NormalDiscountStrategy() },
{ CustomerType.New, new NewCustomerDiscountStrategy() }
};
public static IDiscountStrategy Get(CustomerType type)
=> _strategies[type];
}
//④ 调用
var strategy = DiscountStrategyFactory.Get(order.CustomerType);
var discount = strategy.Calculate(order);
- 优缺点
- 可扩展性极强
- 每个策略逻辑清晰
- 易测试、易维护
- 类数量增加
- 初期显得"设计偏重"
- 需要额外的策略选择机制
三、状态模式(State Pattern)
- 适用场景
"对象行为随状态变化而变化"
判断标准:if / else 依据的是 当前状态,同一方法在不同状态下行为不同,状态之间存在流转关系
典型示例:订单状态(新建 / 已支付 / 已发货 / 已取消),工作流,审批流程,设备状态(开机 / 关机 / 待机)
- 原始 if / else 示例
csharp
public void Pay(Order order)
{
if (order.Status == OrderStatus.Created)
{
order.Status = OrderStatus.Paid;
}
else if (order.Status == OrderStatus.Paid)
{
throw new Exception("订单已支付");
}
else if (order.Status == OrderStatus.Canceled)
{
throw new Exception("订单已取消");
}
}
- 使用状态模式
csharp
//① 状态接口
public interface IOrderState
{
void Pay(OrderContext context);
}
//② 状态上下文
public class OrderContext
{
public IOrderState State { get; set; }
public void Pay()
{
State.Pay(this);
}
}
//③ 具体状态
public class CreatedState : IOrderState
{
public void Pay(OrderContext context)
{
context.State = new PaidState();
}
}
public class PaidState : IOrderState
{
public void Pay(OrderContext context)
{
throw new InvalidOperationException("订单已支付");
}
}
public class CanceledState : IOrderState
{
public void Pay(OrderContext context)
{
throw new InvalidOperationException("订单已取消");
}
}
- 优缺点
- 彻底消除状态判断
- 状态逻辑高度内聚
- 对复杂流程极友好
- 类数量显著增加
- 不适合简单状态
- 初学者理解成本高
四、三者核心对比总结
| 维度 | 卫语句 | 策略模式 | 状态模式 |
|---|---|---|---|
| 解决什么问题 | 前置校验、异常路径 | 不同算法/规则 | 状态驱动行为 |
| 是否消除 if | ❌ | ✅ | ✅ |
| 是否面向对象 | 否 | 是 | 是 |
| 类数量 | 不变 | 增加 | 大量增加 |
| 是否有状态流转 | 无 | 无 | 有 |
| 扩展性 | 低 | 高 | 高 |
| 使用成本 | 极低 | 中 | 高 |
完结撒花~