如何使用具有相同属性的构建器模式和继承

时间:2018-06-04 15:51:37

标签: java design-patterns builder-pattern

事实上,我想问一下我的方法是否正确,因为我可能不应该在这里使用构建器模式。

我目前有以下课程CsvItem

public class CsvItem {
    private CsvItemGroup group;
    private CsvItemEntity entity;
    private String att1;
    private String att2;
    private String att3;
    private String att4;
    private String att5;
    private String att6;
    private String att7;
    private String att8;

    CsvItem(
            CsvItemGroup group,
            CsvItemEntity entity,
            String att1,
            String att2,
            String att3,
            String att4,
            String att5,
            String att6,
            String att7,
            String att8) {

        this.group = group;
        this.entity = entity;
        this.att1 = att1;
        this.att2 = att2;
        this.att3 = att3;
        this.att4 = att4;
        this.att5 = att5;
        this.att6 = att6;
        this.att7 = att7;
        this.att8 = att8;
    }
}

我有一些从CsvItem延伸的子类,CsvItemA

public class CsvItemADW extends CsvItem {

    public CsvItemADW(CsvItemEntity entity,
                  String att1,
                  String att2,
                  String att3,
                  String att4,
                  String att5,
                  String att6,
                  String att7,
                  String att8) {

        super(CsvItemGroup.A, entity, att1, att2, att3, att4, att5, att6, att7, att8);
    }
}

这种方法确实有效,如果我有另一个类CsvItemB,我只需修改构造函数即可发送CsvItemGroup.B

这里的问题是我想在超类中使用构建器模式,以便仅使用我需要的属性,并且无法创建具有空值或空值的构造函数。

我面临的问题是我不想重复代码,如果我在子类中使用构建器模式,我会有很多重复的代码。请注意,超类和子类具有相同的属性,唯一改变的是itemGroup

构建器模式用法示例:

public class CsvItem {

private final CsvItemGroup group;
private final CsvItemEntity entity;
private final String att1;
private final String att2;
private final String att3;
private final String att4;
private final String att5;
private final String att6;
private final String att7;
private final String att8;

private CsvItem(CsvItemBuilder csvItemBuilder) {
    this.group = csvItemBuilder.group;
    this.entity = csvItemBuilder.entity;
    this.att1 = csvItemBuilder.att1;
    this.att2 = csvItemBuilder.att2;
    this.att3 = csvItemBuilder.att3;
    this.att4 = csvItemBuilder.att4;
    this.att5 = csvItemBuilder.att5;
    this.att6 = csvItemBuilder.att6;
    this.att7 = csvItemBuilder.att7;
    this.att8 = csvItemBuilder.att8;
}

public static class CsvItemBuilder{
    private final CsvItemGroup group;
    private final CsvItemEntity entity;
    private String att1;
    private String att2;
    private String att3;
    private String att4;
    private String att5;
    private String att6;
    private String att7;
    private String att8;

    public CsvItemBuilder(CsvItemGroup itemGroup, CsvItemEntity itemEntity) {
        this.group = itemGroup;
        this.entity = itemEntity;
    }

    public CsvItemBuilder withAtt1(String att1) {
        this.att1 = att1;
        return this;
    }

    public CsvItemBuilder withAtt2(String att2) {
        this.att2 = att2;
        return this;
    }

    // ... same with all attX

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

1 个答案:

答案 0 :(得分:5)

这听起来像是用于类层次结构的 Builder模式问题(Effective Java)。你的通用CsvItem就像Book的例子中的Pizza:

public abstract class Pizza {
    final Set toppings;

    Pizza(Builder<?> builder) {
        toppings = builder.toppings.clone();
    }

    public enum Topping {HAM, MUSHROOM, ONION, PEPPER, SAUSAGE}

    abstract static class Builder<T extends Builder> {
        EnumSet toppings = EnumSet.noneOf(Topping.class);
        abstract Pizza build();

        public T addTopping(Topping topping) {
            toppings.add(Objects.requireNonNull(topping));
            return self();
        }

        // Subclasses must override this method to return "this"
        protected abstract T self();
    }
}

然后,您的特定CsvItem就像NyPizza和Calzone:

public class NyPizza extends Pizza {
    private final Size size;

    private NyPizza(Builder builder) {
        super(builder);
        size = builder.size;
    }

    public enum Size {SMALL, MEDIUM, LARGE}


    public static class Builder extends Pizza.Builder<Builder> {
        private final Size size;

        public Builder(Size size) {
            this.size = Objects.requireNonNull(size);
        }

        @Override
        public NyPizza build() {
            return new NyPizza(this);
        }

        @Override
        protected Builder self() {
            return this;
        }
    }
}

public class Calzone extends Pizza {
    private final boolean sauceInside;

    private Calzone(Builder builder) {
        super(builder);
        sauceInside = builder.sauceInside;
    }

    public static class Builder extends Pizza.Builder<Builder> {
        private boolean sauceInside = false; // Default

        public Builder sauceInside() {
            sauceInside = true;
            return this;
        }

        @Override
        public Calzone build() {
            return new Calzone(this);
        }

        @Override
        protected Builder self() {
            return this;
        }
    }
}

使用它:

NyPizza pizza = new NyPizza.Builder(SMALL)
 .addTopping(SAUSAGE).addTopping(ONION).build();
Calzone calzone = new Calzone.Builder()
 .addTopping(HAM).sauceInside().build();

希望它对你有所帮助。