Шаблон Java-компоновщика с нетривиальным деревом подклассов - PullRequest
0 голосов
/ 13 июня 2018

Я знаком с использованием шаблона построителя с обобщениями и подклассами, но я не понимаю, как заставить его работать с нетривиальным деревом подклассов (т. Е. C расширяет B расширяет A).Вот простой пример того, что я пытаюсь сделать:

class A {
    private final int value;

    protected A(ABuilder builder) {
        this.value = builder.value;
    }

    public int getValue() { return value; }

    public static class ABuilder<T extends ABuilder<T>> {
        private int value;

        public T withValue(int value) {
            this.value = value;
            return (T) this;
        }

        public A build() {
            return new A(this);
        }
    }
}

class B extends A {
    private final String name;

    public static BBuilder builder() {
        return new BBuilder();
    }

    protected B(BBuilder builder) {
        super(builder);
        this.name = builder.name;
    }

    public String getName() { return name; }

    public static class BBuilder<U extends BBuilder<U>> extends ABuilder<BBuilder<U>> {
        private String name;

        public U withName(String name) {
            this.name = name;
            return (U) this;
        }

        public B build() {
            return new B(this);
        }
    }
}

Все нормально, если я объявляю BBuilder без универсального типа:

public static class BBuilder extends ABuilder<BBuilder>

Поскольку я хочу, чтобы BBuilder был расширенCBuilder, я пытаюсь использовать тот же тип шаблона CURLYURURRING Template Pattern, что и ABuilder.Но вот так, компилятор видит BBuilder.withValue () как возвращающий ABuilder, а не BBuilder, как я хочу.Это:

    B b = builder.withValue(1)
    .withName("X")
    .build();

не компилируется.Может кто-нибудь увидеть, что я делаю здесь не так, я пробовал разные образцы дженериков, но не могу заставить его работать.

Спасибо всем, кто имеет какие-либо советы.

Ответы [ 2 ]

0 голосов
/ 13 июня 2018

Вы уверены, что вам нужны дженерики?Кажется, эта иерархия прекрасно работает без обобщений.

static class A {
    protected final int value;

    protected A(ABuilder builder) {
        this.value = builder.value;
    }

    public int getValue() {
        return value;
    }

    @Override
    public String toString() {
        return "A{" +
                "value=" + value +
                '}';
    }

    public static ABuilder builder() {
        return new ABuilder();
    }

    public static class ABuilder {
        protected int value;

        public ABuilder withValue(int value) {
            this.value = value;
            return this;
        }

        public A build() {
            return new A(this);
        }
    }

}

static class B extends A {
    protected final String name;

    protected B(BBuilder builder) {
        super(builder);
        this.name = builder.name;
    }

    public String getName() {
        return name;
    }

    @Override
    public String toString() {
        return "B{" +
                "value=" + value +
                ", name='" + name + '\'' +
                '}';
    }

    public static BBuilder builder() {
        return new BBuilder();
    }

    public static class BBuilder extends ABuilder {
        private String name;

        public BBuilder withName(String name) {
            this.name = name;
            return this;
        }

        @Override
        public BBuilder withValue(int value) {
            this.value = value * 2;
            return this;
        }

        public B build() {
            return new B(this);
        }
    }
}

static class C extends B {
    private final String otherName;

    protected C(CBuilder builder) {
        super(builder);
        this.otherName = builder.otherName;
    }

    public String getName() {
        return otherName;
    }

    @Override
    public String toString() {
        return "C{" +
                "value=" + value +
                ", name='" + name + '\'' +
                ", otherName='" + otherName + '\'' +
                '}';
    }

    public static CBuilder builder() {
        return new CBuilder();
    }

    public static class CBuilder extends BBuilder {
        private String otherName;

        public CBuilder withName(String name) {
            this.otherName = name;
            return this;
        }

        public C build() {
            return new C(this);
        }
    }
}

public void test() {
    A a = A.builder().withValue(10).build();
    B b = B.builder().withValue(10).withName("B").build();
    C c = C.builder().withName("C").build();
    System.out.println("a = "+a);
    System.out.println("b = "+b);
    System.out.println("c = "+c);
}
0 голосов
/ 13 июня 2018

Кажется, что ваша ошибка только при объявлении правильного параметра:

class A {

    private final int value;

    public static <T extends Builder<T>> T builderA() {
        return (T)new Builder<>();
    }

    protected A(Builder<? extends Builder<?>> builder) {
        value = builder.value;
    }

    public static class Builder<T extends Builder<T>> {

        private int value;

        public T withValue(int value) {
            this.value = value;
            return (T)this;
        }

        public A build() {
            return new A(this);
        }
    }
}

class B extends A {

    private final String name;

    public static <T extends Builder<T>> T builderB() {
        return (T)new Builder<>();
    }

    protected B(Builder<? extends Builder<?>> builder) {
        super(builder);
        name = builder.name;
    }

    public static class Builder<T extends Builder<T>> extends A.Builder<T> {

        private String name;

        public Builder<T> withName(String name) {
            this.name = name;
            return this;
        }

        public B build() {
            return new B(this);
        }
    }
}

Код клиента:

A a = A.builder().withValue(1).build();
B b = B.builder().withValue(2).withName("xx").build();
...