泛型方法通过类型约束和编译期检查从源头杜绝非法状态注入,而非运行时拦截;它强制使用带语义的值对象(如orderid、money)、受限状态迁移方法及dto与entity分离,实现强类型领域建模。

泛型方法本身不直接“拦截”变量注入,但结合类型约束、编译期检查与领域建模,可从源头杜绝非法状态进入核心实体——这不是运行时防御,而是让错误根本无法通过编译。
用类型约束固化领域规则
领域实体的关键字段(如订单号、金额、状态码)不应是裸的 string 或 int,而应是带语义和校验边界的类型。泛型配合约束能强制这一设计:
- 定义值对象作为泛型参数:例如
OrderId封装非空、符合正则的字符串逻辑,Money<tcurrency></tcurrency>约束货币单位必须实现Currency接口 - 在实体构造函数中只接受这些强类型参数:
Order(OrderId id, Money<usd> total)</usd>,编译器会拒绝传入原始string或double - Go 示例:
func NewOrder[ID ~string, AMT constraints.Ordered](id ID, amount AMT) *Order,其中ID ~string表示底层为 string 但不可与 string 互换,防止误赋值
状态迁移仅通过受限泛型方法暴露
实体状态(如 Pending → Confirmed → Shipped)不能靠 setter 暴露字段,而应由泛型方法控制流转路径:
- 为每种合法状态定义接口:
type Confirmable interface{ CanConfirm() bool } - 泛型方法签名限定输入必须满足该接口:
func (o *Order) Confirm[T Confirmable](t T) error,确保调用前已通过领域规则校验 - C++20 Concepts 可更进一步:
template<validorderstate s> void transition_to(S new_state);</validorderstate>,非法状态类型(如Deleted)直接编译失败
擦除风险下的运行时兜底不等于妥协
Java 等存在泛型擦除的语言,虽无法在运行时获取泛型实参,但可通过组合手段守住底线:
- 构造时做一次反射校验(仅限初始化):检查传入的
List<item></item>是否真由Item实例构成,失败则抛IllegalArgumentException - 关键 setter 加注解 + 编译期 APT:如
@ValidState("Shipped")配合注解处理器,在编译阶段扫描并验证所有状态赋值点 - 将状态枚举与泛型绑定:
enum OrderStatus { PENDING, CONFIRMED };,实体字段声明为private final OrderStatus status;,避免字符串硬编码
拦截非法注入的本质是拒绝“弱类型入口”
所谓“拦截”,不是在数据进来后检查,而是让非法数据根本没有合法通道:
- 禁止 public 字段或无约束 setter;所有状态变更必须走命名明确的、带类型约束的方法(如
ship(TrackingNumber)) - DTO 与 Entity 严格分离:API 层接收
OrderRequest(含原始字段),领域层只构造Order(要求TrackingNumber类型),转换过程即校验点 - 使用 record / sealed class 强化不可变性:Java 14+
record OrderId(String value) implements Identifier,天然防篡改










