标签:oop subclass covariance java
我将一些代码重构为构建器模式,并在子类的构建器子类化时遇到问题.
当我有一个生成器子类,并且尝试在父级中链接一个方法时,它将返回父级生成器,因此我的实例不再有权访问子类方法.
public class App {
public static void main(String[] args) {
Parent p;
p = new App().new ChildBuilder()
.withName("Test")
.withNickName("Test1")
.build();// Doesn't Compile
p = new App().new ChildBuilder()
.withNickName("Test1")
.withName("Test")
.build();
}
class Parent {
public Parent(ParentBuilder builder) {}
}
class Child extends Parent {
public Child(ChildBuilder builder) { super(builder); }
}
class ParentBuilder {
private String name;
public ParentBuilder() {}
public Parent build() { return new Parent(this); }
public ParentBuilder withName(String name) {
this.name = name;
return this;
}
}
class ChildBuilder extends ParentBuilder {
private String nickName;
public ChildBuilder withNickName(String nickName) {
this.nickName = nickName;
return this;
}
}
}
main方法中的第二行将不会编译,因为withName(“ Test”)位于ParentBuilder类上并返回ParentBuilder.对链进行重新排序以调用所有ChildBuilder方法首先可以解决此问题,但是对于使用我的api(包括我自己)的人们来说,这听起来像是一种糟糕的体验.
如果在子项中添加替代,则可以通过协方差使其起作用:
@Override
public ChildBuilder withName(String name) {
super.withName(name);
return this;
}
但这是我不愿维护的许多样板代码(每个父构建器可能有几个子类,因此我需要为父类中的每个方法重写每个子类中的这些方法).
有没有一种方法可以在没有覆盖的情况下做我想做的事情? Java可以在子级中“推断”协变方法吗?
我也担心这个问题表明我在错误地设计建造者.
解决方法:
不,没有推断出的协方差,但是它被奇怪的重复模板模式(或源自C的CRTP)所模仿.
您可以通过添加2个使用CRTP的(打包私有)抽象类(即,参数类型是子类)来解决此问题.将构建器功能移至这些类,然后创建2个空类来扩展抽象构建器.
我还更改了构造函数,使其不直接依赖于构建器,而是依赖于实际参数,因为通常这是这样做的方法,并且在这里使实现更加简洁:
public static void main(String[] args) {
// Both examples now compile
Parent p;
p = new App().new ChildBuilder()
.withName("Test")
.withNickName("Test1")
.build();
p = new App().new ChildBuilder()
.withNickName("Test1")
.withName("Test")
.build();
}
class Parent {
public Parent(String name) {}
}
class Child extends Parent {
public Child(String name, String nickName) { super(name); }
}
abstract class AbstractParentBuilder<T extends AbstractParentBuilder<T>> {
protected String name;
protected AbstractParentBuilder() {}
public Parent build() { return new Parent(name); }
@SuppressWarnings("unchecked")
public T withName(String name) {
this.name = name;
return (T) this;
}
}
class ParentBuilder extends AbstractParentBuilder<ParentBuilder> {}
abstract class AbstractChildBuilder<T extends AbstractChildBuilder<T>> extends AbstractParentBuilder<T> {
protected String nickName;
protected AbstractChildBuilder() {}
public Child build() { return new Child(name, nickName); }
@SuppressWarnings("unchecked")
public T withNickName(String nickName) {
this.nickName = nickName;
return (T) this;
}
}
class ChildBuilder extends AbstractChildBuilder<ChildBuilder> {}
标签:oop,subclass,covariance,java 来源: https://codeday.me/bug/20191109/2010911.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。