多数据源分步填充对象的设计模式选型及Java实现相关问题
适配设计方案
最匹配你需求的是建造者模式(Builder)+ 责任链模式的组合实现,Java生态下这套方案成熟度很高,落地成本低。
- 建造者模式负责封装Fund的半构建状态,避免不完整的Fund实例被非法使用
- 责任链模式负责编排多个数据源的执行顺序,每个数据源只负责自己对应的属性填充,互不感知
疑问解答
1. 在多个类之间传递部分构建的Fund对象是否为合理实践?
直接传递未封装的半完成Fund实例属于不合理实践,很容易出现空指针、状态不一致、中间状态被误用等问题。
但如果用建造者把半构建的Fund实例封装在Builder内部,仅对外暴露属性赋值权限,不暴露未完成的Fund对象,就是非常标准的合理实践。所有数据源只能给Builder写属性,拿不到不完整的Fund,完全规避非法使用风险。
2. 如何保证Fund对象与多个数据源之间的松散耦合?
核心靠抽象层做双向隔离:
- 定义通用的属性填充器接口,所有数据源只依赖这个抽象接口,不需要知道Fund的内部细节,也不需要感知其他数据源的存在
- Fund类仅和自身的Builder耦合,完全不知道任何数据源的存在,不需要关心属性的来源
- 后续新增、删除、替换数据源时,只需要调整填充器实现,不需要修改Fund类,也不会影响其他已有的数据源逻辑
Java代码示例
// Fund实体类,构建完成后只读,不可修改 public class Fund { private String fundCode; private String fundName; private BigDecimal netValue; private String manager; // 其他大量属性省略... // 私有构造器,禁止外部直接实例化 private Fund() {} // 内部Builder类,负责封装半构建状态 public static class FundBuilder { private final Fund fund = new Fund(); // 链式赋值方法 public FundBuilder fundCode(String fundCode) { this.fund.fundCode = fundCode; return this; } public FundBuilder fundName(String fundName) { this.fund.fundName = fundName; return this; } public FundBuilder netValue(BigDecimal netValue) { this.fund.netValue = netValue; return this; } public FundBuilder manager(String manager) { this.fund.manager = manager; return this; } // 构建最终实例,统一做必填项校验 public Fund build() { if (fund.fundCode == null || fund.netValue == null) { throw new IllegalStateException("Fund核心属性缺失,无法完成构建"); } return fund; } } // 仅暴露get方法,保证实例不可变 public String getFundCode() { return fundCode; } public String getFundName() { return fundName; } public BigDecimal getNetValue() { return netValue; } public String getManager() { return manager; } } // 抽象填充器接口,所有数据源实现这个接口 public interface FundAttributePopulator { void populate(Fund.FundBuilder builder); } // 具体数据源1:填充基金基础信息 public class FundBaseInfoPopulator implements FundAttributePopulator { @Override public void populate(Fund.FundBuilder builder) { // 调用自身数据源获取数据后赋值,省略数据查询逻辑 builder.fundCode("000001") .fundName("混合型测试基金"); } } // 具体数据源2:填充基金净值数据 public class FundNetValuePopulator implements FundAttributePopulator { @Override public void populate(Fund.FundBuilder builder) { // 调用自身数据源获取数据后赋值,省略数据查询逻辑 builder.netValue(new BigDecimal("1.876")); } } // 具体数据源3:填充基金经理信息 public class FundManagerPopulator implements FundAttributePopulator { @Override public void populate(Fund.FundBuilder builder) { // 调用自身数据源获取数据后赋值,省略数据查询逻辑 builder.manager("李四"); } } // 编排执行类,负责串起所有填充流程 public class FundAssemblyService { // 按业务顺序注入所有填充器,Spring环境下可以直接自动注入List private final List<FundAttributePopulator> populators; public FundAssemblyService(List<FundAttributePopulator> populators) { this.populators = populators; } public Fund assembleFund() { Fund.FundBuilder builder = new Fund.FundBuilder(); for (FundAttributePopulator populator : populators) { populator.populate(builder); } return builder.build(); } }
内容的提问来源于stack exchange,提问作者serah
相关产品推荐
相关产品推荐

