首页/开发/代码质量与评审速查/手法:Introduce Special Case(引入特例)
重构手法62 条

手法:Introduce Special Case(引入特例)

为「特殊值」(未知客户、缺失配置)建立可复用对象:把判空与兜底逻辑收进特例对象,消除调用方的重复条件判断;空对象模式是它的常见形态。

Introduce Special Case 是什么

为「特殊值」建立可复用的对象:未知客户、缺失配置、空集合。把判空与兜底逻辑收进特例对象后,调用方不再遍地形如 if (x == null),默认行为也集中在一处定义。空对象模式(Null Object)是它最常见的形态;《重构》里把它归入简化条件表达式的一组手法。

基本信息

场景到处判 null、缺省值,默认行为在多处重复
形态Null Object、Unknown Customer、Empty Collection
收益调用方不再遍地形如 if (x == null)
前提默认行为是确定的、可命名的业务语义

典型用法

  • 未登录用户用一个匿名用户对象承载默认权限与默认昵称
  • 缺失配置用带默认值的配置对象替代 null,避免每个读取点判空
  • 空集合用迭代器模式的空对象,循环代码不必特判
  • 上游系统查不到记录时返回「未知实体」,展示层直接显示占位文案
  • 把散落在各处的默认值集中到特例对象的构造里,改默认值只改一处

Java 示例

Java 示例
interface Customer {
    String name();
    BillingPlan plan();
    boolean isUnknown();
}

class UnknownCustomer implements Customer {
    @Override public String name()  { return "occupant"; }
    @Override public BillingPlan plan() { return BillingPlan.basic(); }
    @Override public boolean isUnknown() { return true; }
}

// 调用方:不再需要判空
String who = site.customer().name();

适用与不适用

情况处理原因
缺失但有明确默认行为特例对象把默认语义显式化
缺失即代表异常抛出异常静默兜底会掩盖故障
特例需要承载状态变化慎重使用共享实例可能被意外改坏
默认行为频繁变化先提取默认值避免特例对象频繁改动
特例对象应当不可变,并且通常是单例:它会被很多调用点共享,一旦有某个调用方改了它的状态,影响面不可控。
用特例对象吞掉真实错误是常见陷阱:把「查不到」和「下游超时」都返回同一个未知对象,故障就再也不会被上报。先分清「缺失」与「失败」,只对前者使用特例。

易错点

  • 把特例当普通对象修改:共享实例被意外改坏,故障难复现
  • 用特例吞掉真实错误:该报错的分支被静默兜底,监控失去信号
  • 特例对象承担过多默认逻辑:变成一个隐形的业务规则集中营,改动风险高
  • 系统边界处直接返回 null 却只在部分调用点用特例:两套约定并存,判空代码依旧散落
  • 只在读取侧引入特例而写入侧仍收 null:两套约定并存,调用方仍需判空

数据来源与参考

  • 《重构》第 2 版 · 第 10 章(Introduce Special Case)
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌