
当类型码只是用来标识类别、不参与行为逻辑时,用一个专用类来封装它,比用 int 或 string 更安全、更清晰。
适用场景:类型码只做“标签”,不驱动分支逻辑
比如员工血型(A/B/AB/O)、订单优先级("low"/"normal"/"high")、国家编码("CN"/"US"/"JP")——这些值本身不改变对象行为,也不触发 if 或 switch 分支。它们只是信息性标识。
- 原始代码里常写成 public const int A = 0; 或直接用字符串字面量,容易拼错、难搜索、无类型约束
- 编译器无法阻止传入非法值,比如把 99 当作血型传进去
- 调用处看不到语义,只能靠注释或约定,可读性差
核心做法:建一个不可变的轻量类,预定义合法实例
不是简单换成枚举,而是创建一个真实类,把每个合法类型码作为该类的静态只读实例暴露出来。
- 类内部用 private 构造函数 + public static readonly 字段,确保只有预设值可用
- 提供有意义的方法,比如 BloodGroup.A.equals(BloodGroup.B) 或 Priority.HIGH.higherThan(Priority.LOW)
- 原字段类型从 int/string 改为这个新类,所有赋值和比较都走类接口
和枚举、子类的关键区别
枚举虽有命名,但底层仍是整数,编译器不阻止强制转换;子类用于行为差异大的场景,会引入继承结构。而“以类取代类型码”专注解决标识混乱问题,不增加行为复杂度。
- 它不继承、不抽象、不重写方法,只是一个“带名字的值”
- 适合未来可能要加校验、格式化、本地化等小功能的场景
- 如果后续发现不同类型码开始影响行为(比如血型影响用药规则),再考虑升级为策略或子类
实际改法示例(C#)
替换前:
public class Employee { public string BloodType { get; set; } // "A", "B", ... }替换后:
public sealed class BloodGroup{
public static readonly BloodGroup A = new BloodGroup("A");
public static readonly BloodGroup B = new BloodGroup("B");
public static readonly BloodGroup AB = new BloodGroup("AB");
public static readonly BloodGroup O = new BloodGroup("O");
private readonly string _code;
private BloodGroup(string code) => _code = code;
public override string ToString() => _code;
}
public class Employee { public BloodGroup BloodType { get; set; }
这样 BloodType 只能是那四个预设值之一,编译期就受保护。










