从父类返回子类 [英] Return child class from parent class
问题描述
我有一个构建器类,它从大多数方法返回以允许菊花链。要使这个工作与子类,我想父方法返回子的实例,以便子方法将可用链接到结束。
public class BaseBuilder< T extends BaseBuilder< T> {
public T buildSomething(){
doSomeWork();
/ *选项#1:* / return this; //Type mismatch:can not convert from BaseBuilder< T> to T
/ * OPTION#2:* / return T.this; //Type mismatch:can not convert from BaseBuilder< T> to T
/ * OPTION#3:* / return(T)this; //类型安全性:从SqlBuilder< T>到T
}
的未选中的转换public class ChildBuilder extends BaseBuilder< ChildBuilder> {}
选项#1和#2会导致编译错误,选项#3会产生警告一个可以用 @SuppressWarnings(unchecked)
)抑制。这里有更好的方法吗?
声明 ChildBuilder扩展BaseBuilder< ChildBuilder> code>某种程度上表示代码气味,似乎违反了DRY。在此示例中,
BaseBuilder
只能使用 ChildBuilder
进行参数化,因此应该是多余的。
我宁愿重新思考我是否真的想要过度架构这个,我会尝试把所有的子构建器的方法放入 BaseBuilder
。然后我可以简单地从所有支持链接的方法返回 this
。
如果我仍然认为我会受益将构建器方法的特定组分离成它们自己的类,那么我将优先使用组合,因为不推荐仅将代码重用为继承。
假设我们有两个子类 BaseBuilder :
类BuilderA扩展BaseBuilder< BuilderA> {
BuilderA buildSomethingA(){return this; }
}
class BuilderB extends BaseBuilder< BuilderB> {
BuilderB buildSomethingB(){return this; }
}
如果需要链接 buildSomethingA
和 buildSomethingB
like:
builder.buildSomething ().buildSomethingA()。buildSomethingB();
我们不能将子类方法移动到 BaseBuilder
;但是想象下也有 BuilderC
,这些方法没有意义,不应该继承自 BaseBuilder
。
如果我们仍然将这两个方法移动到超类,下一次三个其他方法和下一次...我们将最终导致一个超类负责90具有大量代码的整个层次结构的职责百分比:
if((This instanceof BuilderB)&& flag1&& flag2){
...
} else if((this instanceof BuilderC)&&& amp; flag1&&!flag2&&& b $ b ...
} else if ...
是类似DSL的DSL:
builder.buildSomething1()。buildSomething2()
.builderA()
.buildSomethingA1()。buildSomethingA2()
.end()
.buildSomething3()
.builderB()
.buildSomethingB()
。
这里 end()
c $ c> builder 实例,因此您可以链接更多的方法或启动一个新的子构建器。
构建器可以从任何他们需要的继承(否则它们只能扩展 BaseBuilder
),并且可以有自己有意义的层次结构或组合。
I have a builder class that returns itself from most methods to allow for daisy-chaining. To make this work with child classes, I want the parent methods to return instances of the child so that child methods will be available to chain to the end.
public class BaseBuilder<T extends BaseBuilder<T>> {
public T buildSomething() {
doSomeWork();
/* OPTION #1: */ return this; // "Type mismatch: cannot convert from BaseBuilder<T> to T"
/* OPTION #2: */ return T.this; // "Type mismatch: cannot convert from BaseBuilder<T> to T"
/* OPTION #3: */ return (T) this; // "Type safety: Unchecked cast from SqlBuilder<T> to T"
}
}
public class ChildBuilder extends BaseBuilder<ChildBuilder> {}
Options #1 and #2 result in compilation errors, and option #3 a warning (albeit one that can be suppressed with @SuppressWarnings("unchecked")
). Is there a better approach here? How can I safely downcast Basebuilder to Childbuilder?
The declaration ChildBuilder extends BaseBuilder<ChildBuilder>
somehow indicates a code smell and seems to violate DRY. In this example BaseBuilder
can be parametrized only with ChildBuilder
and nothing else, so it should be redundant.
I would rather rethink whether I really want to over-architecture this and I would try to put all the methods from child builders into the BaseBuilder
. Then I can simply return this
from all the methods supporting chaining.
If I still think that I will benefit by separating specific groups of builder methods into their own classes, then I would give preference to composition, because applying inheritance only for code reuse is not recommended.
Suppose we have two subclasses of the BaseBuilder
:
class BuilderA extends BaseBuilder<BuilderA> {
BuilderA buildSomethingA() { return this; }
}
class BuilderB extends BaseBuilder<BuilderB> {
BuilderB buildSomethingB() { return this; }
}
What if the need arises to chain buildSomethingA
and buildSomethingB
like:
builder.buildSomething().buildSomethingA().buildSomethingB();
We will not be able to do it without moving the subclass methods to the BaseBuilder
; but imagine there is also BuilderC
for which those methods don't make sense and shouldn't be inherited from the BaseBuilder
.
If we nevertheless move these two methods to the superclass, and next time three other methods and next time... we'll end up with a superclass responsible for 90% of the duties of the entire hierarchy with plenty of code like:
if ((this instanceof BuilderB) && !flag1 && flag2) {
...
} else if ((this instanceof BuilderC) && flag1 && !flag2 && thing != null) {
...
} else if ...
The solution I like more is a DSL like:
builder.buildSomething1().buildSomething2()
.builderA()
.buildSomethingA1().buildSomethingA2()
.end()
.buildSomething3()
.builderB()
.buildSomethingB()
.end();
Here end()
returns the builder
instance so you can chain more of its methods or start a new sub-builder.
This way the (sub)builders can inherit from whatever they need to (otherwise they must extend only the BaseBuilder
) and can have their own meaningful hierarchies or compositions.
这篇关于从父类返回子类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!