时间:2025-09-08 22:55
人气:
作者:admin
还在用传统的builder模式来实例化构建对象吗?来,给你的程序注入点新鲜血液????
在复杂的业务系统开发中,我们经常面临如何优雅构建数据对象的挑战。传统的构造器模式在业务语义表达方面存在明显不足。今天我们将深入分析一种基于业务语义导向的Builder模式在AuditSaveVO类中的精妙实现。
常规的对象构建方式通常采用以下几种模式:
// 1. 多参数构造器 - 参数顺序易错
new AuditSaveVO(orderNo, bizType, auditorId, auditorName, node, remark, remarkType, statusDesc);
// 2. Setter链式调用 - 业务关联性丢失
new AuditSaveVO()
.setBizOrderNo("ORD001")
.setBizType(BizTypeEnum.AGENT_CHANGE)
...
.setAuditorId(1001L);
// 3. builder模式链式赋值
AuditSaveVO.builder()
.bizOrderNo(r"ORD001")
.bizType(BizTypeEnum.AGENT_CHANGE)
...
.build();
这些方式存在三个核心问题:
bizOrderNo与业务类型bizType是紧密关联的业务概念,却被拆分为独立操作我们的AuditSaveVO采用了全新的构建范式:
/**
* 审核记录持久化VO - 采用业务语义化Builder模式
* 构建对象请使用 AuditSaveVO.builder()
*/
@ToString
@Getter
public class AuditSaveVO implements Serializable {
// 字段定义...
private AuditSaveVO() {} // 私有构造器
/**
* ★★★ 构建器入口方法 ★★★
*/
public static BizOrderStep builder() {
return new AuditSaveVOBuilder();
}
// 构建步骤接口定义
private interface BizOrderStep {
AuditNodeStep withBizOrder(String bizOrderNo, BizTypeEnum bizType);
}
private interface AuditNodeStep {
OperationStep withAuditNode(AuditNodeEnum auditNodeEnum);
}
// 更多步骤接口...
// 构建器实现
private static class AuditSaveVOBuilder implements BizOrderStep, AuditNodeStep, OperationStep, RemarkStep, AuditStatusDescStep, BuildStep {
private final AuditSaveVO auditSaveVO = new AuditSaveVO();
@Override
public AuditNodeStep withBizOrder(String bizOrderNo, BizTypeEnum bizType) {
// 业务单元聚合:订单号+业务类型
auditSaveVO.bizOrderNo = bizOrderNo;
auditSaveVO.bizType = bizType;
return this;
}
// 其他接口实现...
}
}
核心是三步:
实际应用效果如下:
// 业务代码中的使用示例,对象构造变得so easy!
AuditSaveVO record = AuditSaveVO.builder()
.withBizOrder(application.getId(), BizTypeEnum.APPLICATION_AUDIT)
.withAuditNode(AuditNodeEnum.FIRST_APPROVAL)
.withAuditor(currentUser.getId(), currentUser.getName())
.withRemark("材料齐全,符合要求", "APPROVE")
.withAuditStatusDesc("一审通过")
.build();
业务单元聚合设计
// 将业务上紧密关联的字段组合在一起设置
.withBizOrder("ORD001", BizTypeEnum.AGENT_CHANGE)
这种方式保持了业务概念的完整性,避免了字段分散设置带来的语义割裂。业务意图更加明确,大大提升代码可读性。
构建流程强约束
通过接口返回值类型限定,确保了构建步骤必须按照业务逻辑顺序执行:
withBizOrder → withAuditNode → withAuditor → withRemark → withAuditStatusDesc → build
有了这个强制约束,开发者再无需care、无需worry是否忘记给个别field赋值,从而提高开发效率。
编译期安全保证
由于构建步骤的接口约束,开发者无法跳过必需步骤或颠倒顺序,大大减少了对象构建相关的BUG。
非必需字段可不赋值————灵活性的拿捏
对于AuditSaveVO来说,假设auditStatusDesc在对象构造时可以忽略赋值,则我们可以修改前面的RemarkStep这个interface,为其添加build方法,即可跳过withAuditStatusDesc,直接调用最终的build方法。
AuditSaveVO record = AuditSaveVO.builder()
.withBizOrder(application.getId(), BizTypeEnum.APPLICATION_AUDIT)
.withAuditNode(AuditNodeEnum.FIRST_APPROVAL)
.withAuditor(currentUser.getId(), currentUser.getName())
.withRemark("材料齐全,符合要求", "APPROVE")
//**`RemarkStep`这个interface有`build`方法,可跳过`withAuditStatusDesc`直接调用`build`完成对象的构建
//.withAuditStatusDesc("一审通过")
.build();
虽然内聚式的Builder设计已经解决了业务语义表达的问题,但从架构角度出发,我们可以进一步优化,将Builder从VO主体中完全分离,实现更清晰的职责划分。
分离的目的:
// AuditSaveBuildSteps.java - 独立的构建步骤接口定义
/*此class不对package外暴露*/ interface AuditSaveBuildSteps {
interface BizOrderStep {
AuditNodeStep withBizOrder(String bizOrderNo, BizTypeEnum bizType);
}
interface AuditNodeStep {
OperationStep withAuditNode(AuditNodeEnum auditNodeEnum);
}
// 其他步骤接口...
}
// AuditSaveVOBuilder.java - 独立的构建器实现
/*此class不对package外暴露*/ class AuditSaveVOBuilder implements AuditSaveBuildSteps.BizOrderStep,
AuditSaveBuildSteps.AuditNodeStep,
AuditSaveBuildSteps.OperationStep,
AuditSaveBuildSteps.RemarkStep,
AuditSaveBuildSteps.AuditStatusDescStep,
AuditSaveBuildSteps.BuildStep {
private final AuditSaveVO auditSaveVO = new AuditSaveVO();
private AuditSaveVOBuilder() {}
public static AuditSaveBuildSteps.BizOrderStep create() {
return new AuditSaveVOBuilder();
}
@Override
public AuditSaveBuildSteps.AuditNodeStep withBizOrder(String bizOrderNo, BizTypeEnum bizType) {
auditSaveVO.bizOrderNo(bizOrderNo);
auditSaveVO.bizType(bizType);
return this;
}
// 其他接口实现...
}
// AuditSaveVO.java - 简化后的值对象
@Getter
@Setter
public class AuditSaveVO implements Serializable {
// 字段定义
/**
* ★★★ 提供构建器入口方法 ★★★
*/
public static AuditSaveBuildSteps.BizOrderStep builder() {
return AuditSaveVOBuilder.create();
}
}
需要说明的一点是:将Builder从VO中分离,破坏了AuditSaveVO的field的可访问性。————我们不希望AuditSaveVO具有public的setter,因为我们期望外部使用builder模式来构建对象。 为了达到这次重构的目的,特做了一个折中,将AuditSaveVO的field设置为默认的package-private。
// 可以独立测试构建器
@Test
void testBuilderWithBizOrder() {
AuditSaveVOBuilder builder = new AuditSaveVOBuilder();
AuditSaveBuildSteps.AuditNodeStep nextStep = builder.withBizOrder("test", BizTypeEnum.AGENT_CHANGE);
assertNotNull(nextStep);
}
// 可以Mock构建器
@Mock
private AuditSaveBuildSteps.BizOrderStep builderMock;
使用端 → AuditSaveBuildSteps(接口) ← AuditSaveVOBuilder(实现)
↑
AuditSaveVO(值对象)
这种依赖关系确保了:
业务语义化的Builder模式通过巧妙的接口设计和步骤约束,彻底解决了复杂对象构建中的业务语义表达问题。这种程序设计思维的本身,正是高质量软件开发的精髓所在。
而通过将Builder从VO中分离的架构优化,我们进一步获得了更清晰的职责划分、更好的可测试性和更强的扩展能力。
这种Builder模式特别适合以下场景:
当看到一些不好的代码时,会发现我还算优秀;当看到优秀的代码时,也才意识到持续学习的重要!--buguge
本文来自博客园,转载请注明原文链接:https://www.cnblogs.com/buguge/p/19080855
上一篇:并发编程中的乐观锁与悲观锁