Builder模式疑问:ConcreteRequest#getLocalValue不可访问但build可用的原因
问题分析与解决
核心原因
这大概率是因为你的Builder类的方法返回类型没有正确适配子类。举个典型的错误实现场景:
// 父类Builder public abstract class AbstractRequestBuilder { protected String globalValue; public AbstractRequestBuilder globalValue(String globalValue) { this.globalValue = globalValue; return this; } public AbstractRequest build() { AbstractRequest request = new AbstractRequest(); request.setGlobalValue(globalValue); return request; } } // 子类Builder public class ConcreteRequestBuilder extends AbstractRequestBuilder { private String localValue; public ConcreteRequestBuilder localValue(String localValue) { this.localValue = localValue; return this; } @Override public ConcreteRequest build() { ConcreteRequest request = new ConcreteRequest(); request.setGlobalValue(globalValue); request.setLocalValue(localValue); return request; } }
如果调用时是这样:
ConcreteRequest request = new ConcreteRequestBuilder() .globalValue("test") // 这里返回的是AbstractRequestBuilder类型 .localValue("local") // 编译报错,因为父类Builder没有这个方法 .build();
build能正常使用,是因为你在子类Builder里覆写了build方法,返回ConcreteRequest类型;但父类的通用参数方法返回的是父类Builder类型,导致链式调用中途类型降级,找不到子类的localValue方法。
正确实现方式
用泛型自限定保证父类Builder方法返回子类Builder类型:
// 父类Builder,使用泛型自限定 public abstract class AbstractRequestBuilder<T extends AbstractRequestBuilder<T>> { protected String globalValue; @SuppressWarnings("unchecked") public T globalValue(String globalValue) { this.globalValue = globalValue; return (T) this; } public abstract AbstractRequest build(); } // 子类Builder,指定泛型参数为自身 public class ConcreteRequestBuilder extends AbstractRequestBuilder<ConcreteRequestBuilder> { private String localValue; public ConcreteRequestBuilder localValue(String localValue) { this.localValue = localValue; return this; } @Override public ConcreteRequest build() { ConcreteRequest request = new ConcreteRequest(); request.setGlobalValue(globalValue); request.setLocalValue(localValue); return request; } }
这样链式调用的类型始终是ConcreteRequestBuilder,就能正常访问localValue方法:
ConcreteRequest request = new ConcreteRequestBuilder() .globalValue("test") .localValue("local") .build();
额外注意点
- DTO类的继承关系要和Builder类的继承对应,保证泛型绑定正确。
- 父类Builder尽量用抽象方法定义
build,由子类实现具体的DTO实例化逻辑,避免类型不匹配。
内容的提问来源于stack exchange,提问作者jnemecz
相关产品推荐
相关产品推荐

