У меня есть следующий код, реализующий абстрактный построитель (как в эффективной книге Java):
interface I {
I ret();
}
abstract class A implements I {
private String s = "";
A(Builder b) {
s = b.s;
}
@Override
public I ret() {
String s = "some new string from calc.";
//HERE I NEED TO CONSTRUCT class B
//THIS IS PROBLEMATIC LINE BELOW <<<<--------------------------------------
return new Builder<>().withString(s).build();
}
static abstract class Builder<T extends Builder<T>> {
String s = "";
T withString(String s) {
this.s = s;
return self();
}
protected abstract A build();
//simulated self-type idiom
protected abstract T self();
}
}
class B extends A {
private B(A.Builder b) {
super(b);
}
static class Builder extends A.Builder<Builder> {
@Override
protected B build() {
return new B(this);
}
@Override
protected Builder self() {
return this;
}
}
}
и это небольшой вариант использования
public static void main(String[] args) {
I b = new B.Builder().withString("bclass").build();
I b2 = b.ret(); //<---- this one should construct new immutable B
}
Я хочу сделать следующее: из метода ret()
в классе A
я хотел бы создать неизменяемый объект, не знающий родительского типа, поэтому в моем примере это будет новый класс B
с новой внутренней строкой.
Проблема в том, что класс A
не знает о классе B
, поскольку B
является его родительским.
Возможно ли что-то подобное, не прибегая к дженерикам?
Если бы я использовал изменяемый класс, это было бы так же просто, как this.s = newS;
.
ОБНОВИТЬ
abstract class A implements I {
private String s = "";
A(Builder b) {
s = b.s;
}
@Override
public I ret() {
String s = "SOME NEW STING FROM CALCULATION";
return builder().withString(s).build();
}
abstract Builder<?> builder();
static abstract class Builder<T extends Builder<T>> {
String s = "";
T withString(String s) {
this.s = s;
return self();
}
protected abstract A build();
//simulated self-type idiom
protected abstract T self();
}
}
class B extends A {
B(A.Builder b) {
super(b);
}
@Override
Builder builder() {
return new Builder();
}
static class Builder extends A.Builder<Builder> {
@Override
protected B build() {
return new B(this);
}
@Override
protected Builder self() {
return this;
}
}
}
Я удалил много кода, чтобы он стал чище. Просто сконцентрировался на своей проблеме.
Вам необходимо предоставить абстрактный метод в A
для создания подходящего экземпляра Builder
:
abstract Builder<A> toBuilder();
Затем реализуйте это в конкретных подклассах и вызовите:
return toBuilder().withString(s).build();
спасибо, выглядит хорошо. Надеюсь, что эта строчка abstract Builder<?> builder();
такая как надо делать? Я обновил пример новым кодом.
Что сюда добавляет строитель? Разве вы не можете просто вызвать (частный?) Конструктор напрямую?