首页 > 解决方案 > JAVA中具有继承的生成器模式

问题描述

假设我有一个从另一个类扩展的类:

class Parent{
    private String p1;
    public void setP1(String p1){
        this.p1 = p1;
    }
}
class Child extends Parent{
    private int c1;
    public void setC1(int c1){
        this.c1 = c1;
    }
}

我使用 Builder Pattern 来创建 Parent 类的一个实例:


class ParentBuilder{
    aParent(){ return new ParentBuilder()}


    with(String p1){
        this.p1 = p1;
    }

    public Parent build(){
        Parent parent = new Parent();
        parent.setP1(this.p1);
        return parent;
    }
}

我如何使用 Child 类的构建器模式来做类似的事情

aParent().with("test").build();
aChild().with(4).build();
aChild().with(4).with("test").build();
aChild().with("test").with(4).build();

标签: javainheritancebuilder

解决方案


如果您有构建器所需的类层次结构,则应该使用它们自己的层次结构正确实现构建器。

正确的构建器实现不允许设置不属于构建对象的字段。例如,如果Parent没有c1字段,则不应允许通过设置它parentBuilder().withC1(val).build();

例如,如果您有以下对象层次结构:

        GrandPa
           |
        Parent
           |
          / \
    Child1   Child2

按照以下代码创建构建器的层次结构是合理的:

与建设者的爷爷班:

public class GrandPa {
    private Integer gp;

    public void setGp(Integer gp) {
        this.gp = gp;
    }

    public static class GrandPaBuilder extends 
                GrandPaBuilderWithResult<GrandPaBuilder, GrandPa> {

        public static GrandPaBuilder grandPaBuilder() {
            return new GrandPaBuilder();
        }

        @Override
        public GrandPa build() {
            GrandPa grandPa = new GrandPa();
            grandPa.setGp(gp);

            return grandPa;
        }
    }

    public static abstract class GrandPaBuilderWithResult<T extends 
                GrandPaBuilderWithResult<T, R>, R extends GrandPa> {

        Integer gp;
        public T withGP(Integer gp) {
            this.gp = gp;
            return (T) this;
        }

        public abstract R build();
    }
}

带有构建器的父类:

public class Parent extends GrandPa {
    private String p;

    public void setP(String p) {
        this.p = p;
    }

    public static class ParentBuilder extends 
                ParentBuilderWithResult<ParentBuilder, Parent> {

        public static ParentBuilder parentBuilder() {
            return new ParentBuilder();
        }

        @Override
        public Parent build() {
            Parent parent = new Parent();
            parent.setGp(gp);
            parent.setP(this.p);

            return parent;
        }
    }

    public static abstract class ParentBuilderWithResult<T extends 
                ParentBuilderWithResult<T, R>, R extends Parent> extends 
                GrandPaBuilderWithResult<T, R> {

        protected String p;

        public T withP(String p) {
            this.p = p;
            return (T) this;
        }
    }
}

以及带有建设者的子类:

public class Child1 extends Parent {

    private Double c1;

    public void setC1(Double c1) {
        this.c1 = c1;
    }

    public static class Child1Builder extends 
                ParentBuilderWithResult<Child1Builder, Child1> {

        private Double c1;

        public static Child1Builder child1Builder() {
            return new Child1Builder();
        }

        public Child1Builder withC1(Double c1) {
            this.c1 = c1;
            return this;
        }

        @Override
        public Child1 build() {
            Child1 child1 = new Child1();
            child1.setGp(gp);
            child1.setP(p);
            child1.setC1(this.c1);

            return child1;
        }
    }
}

public class Child2 extends Parent {

    private Double c2;

    public void setC2(Double c2) {
        this.c2 = c2;
    }

    public static class Child2Builder extends 
                ParentBuilderWithResult<Child2Builder, Child2> {

        private Double c2;

        public static Child2Builder child2Builder() {
            return new Child2Builder();
        }

        public Child2Builder withC2(Double c2) {
            this.c2 = c2;
            return this;
        }

        @Override
        public Child2 build() {
            Child2 child2 = new Child2();
            child2.setGp(gp);
            child2.setP(p);
            child2.setC2(this.c2);

            return child2;
        }
    }
}

请注意在构建器中使用自绑定泛型始终只返回所需的对象引用。此实现是安全的,并且不允许通过构建器将错误放入您的代码中。

您可以通过以下方式使用它们:

GrandPa grandPa = GrandPa.GrandPaBuilder.grandPaBuilder().withGP(1).build();
Parent parent = Parent.ParentBuilder.parentBuilder().withGP(2).withP("p").build();
Child1 child1 = Child1.Child1Builder.child1Builder().withGP(3).withP("p1").withC1(1D).build();
Child2 child2 = Child2.Child2Builder.child2Builder().withGP(3).withP("p2").withC2(2D).build();

推荐阅读