发布于2026-07-08 阅读(0)
扫一扫,手机访问
Ja va 8 带来的一个很有意思的变化是,interface 里终于可以写 static 方法了。从领域驱动设计的角度来看,这可不是什么语法糖——它实实在在地为我们搭建领域工具函数提供了一种原生支持,既不需要抽象类,也犯不着搞个工具类实例,更不用引入那些绕来绕去的继承关系。说白了,这就是DDD里常说的“把领域语义焊死在代码里,别让基础设施层把它冲淡了”。

先聊点具体的。所谓“领域工具函数”,本质上就是那些只依赖输入参数、表达业务意图的逻辑判断。比如在订单域里,“这笔订单算不算高价值”“当前状态能不能取消”,这些判断说到底只跟金额、状态枚举、时间戳这些参数有关,跟 Order 实体里面具体怎么存的、有没有关联表没半毛钱关系。那么,怎么组织这类逻辑才够“领域”?
你可能会问,这和单独弄一个工具类有什么区别?区别就在于“归属感”——这些方法长在 domain 包下的 interface 里,比如 OrderRules,天然就带着业务上下文。方法体里只拿入参做计算,不访问 this,不读写任何字段,更不会去调用非静态成员。返回值明确,没有副作用。这正是纯函数的核心特征,也是后续可测试、可复用的基石。
一个简单的例子:判断是否满足加急配送条件,签名就是 isEligibleForExpressShipping(OrderStatus status, BigDecimal amount)。入参清晰,逻辑聚焦,测试时只需要传不同的状态和金额就行,完全不需要 mock 任何 Order 实例。
有一点得特别拎清楚:别把你那些 StringUtils、DateUtils 的通用能力往领域 interface 里塞。领域工具函数必须带上下文,不能写成纯工具套路。
shouldEscalateToManager(IncidentSeverity severity, LocalDateTime reportedAt)——这说的是事故升级规则,一看就知道是哪个领域的。formatMoney(BigDecimal value)——格式化是表现层该干的事,领域层不应该操心这些。关键在于,方法名和参数类型本身就在声明“我是哪块业务的判断逻辑”。如果你只是在 interface 里写了一堆格式化或者校验的通用方法——那本质上还是一种面向过程的散装工具,只不过换了个马甲而已。
单打独斗的静态方法适合原子判断,但真实业务往往是多条规则叠加。这时候,default 方法就派上用场了。静态方法负责底层的“是与否”,比如 isOverThreshold()、isWithinBusinessHours(),而 default 方法则在这基础上组装出更高层级的业务条件,比如 requiresImmediateReview()。
这样做的好处是:静态方法保持纯粹的无状态性,不会被意外篡改;default 方法则提供了一个面向领域的接口契约,调用方看到的是业务语义,而不是一堆散落的 if 判断。
interface 静态方法虽然简洁,但用起来也得留几个心眼。不能访问实现类的私有或包级字段——这其实是个优势,它倒逼你把所有依赖都通过参数显式传入,可读性和可测性都上去了。另外要注意,static 方法不能被子接口“重写”,只能被隐藏,也就是说子接口里如果写一个同名 static 方法,父接口的那个就相当于被覆盖掉了。所以命名一定要稳定,别随心所欲变更。
最后需要提醒的是:I/O、远程调用、缓存操作这类事情,别往领域工具函数里塞。领域工具函数应该是确定性的——同样的输入一定得到同样的输出。任何可能的延迟或异常,都应该交给上层应用服务去处理。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8