Java 使用抽象生成器扩展抽象类与使用具体类和具体生成器

Java 使用抽象生成器扩展抽象类与使用具体类和具体生成器,java,generics,inheritance,design-patterns,builder,Java,Generics,Inheritance,Design Patterns,Builder,我想在我即将完成的一些工作中使用builder模式,这些工作在层次结构中有几个类。基类将至少有9个字段要开始,不同的子类可以分别添加2-4个更多的字段。这将很快失去控制,基于这个确切的原因,builder模式对我很有吸引力。我在书和文章中初步接触到了建设者模式。他们很有帮助,但对如何扩展这种模式一无所知。我试图自己实现这个,但是我遇到了每个子类的构造函数的问题,因为我不知道如何将生成器中收集的数据传递给超类。我一直在寻找答案,下面是我的发现 本文给出了如何使用抽象生成器扩展抽象类的示例。这也是基

我想在我即将完成的一些工作中使用builder模式,这些工作在层次结构中有几个类。基类将至少有9个字段要开始,不同的子类可以分别添加2-4个更多的字段。这将很快失去控制,基于这个确切的原因,builder模式对我很有吸引力。我在书和文章中初步接触到了建设者模式。他们很有帮助,但对如何扩展这种模式一无所知。我试图自己实现这个,但是我遇到了每个子类的构造函数的问题,因为我不知道如何将生成器中收集的数据传递给超类。我一直在寻找答案,下面是我的发现

本文给出了如何使用抽象生成器扩展抽象类的示例。这也是基于此

我喜欢这个示例,因为它允许您轻松地扩展这些类,但在我看来,这也违背了使用生成器模式的目的,因为方法
withS(String s)
withI(int I)
的行为很像setter方法。此外,此方法将基类和生成器类的字段保留为受保护的字段,而不是私有字段

这是我的一个


我意识到你不能像我在这里展示的那样实例化一个对象,但是还有其他的方法吗?这可能是工厂要去的地方吗?也许我只是对构建器模式的总体假设有误。:)如果是这样的话,有更好的方向吗?

你的第一个例子不错,但我认为这不是你想要的

我仍然有点不确定你到底想要什么,但是看到你的例子不适合你,我想我会给你一两个我自己的例子

任何新类型,都会有自己的生成器,接受其父级的生成器。 如您所见,这类似于:

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

    protected NutritionFacts(Builder builder) {
        calories = builder.calories;
    }
在你的例子中

然而,这也很快失去控制,变量和子类的数量越来越多

另一种选择是使用动态变量,请看以下内容: 马丁·福勒(Martin Fowler)写了一篇很好的文章,详细说明了所有的利弊

无论如何,这是我的第二个例子:

public class Demo {

    public static void main(String[] args) {
        ConcreteBuilder builder = new ConcreteBuilder();
        Concrete concrete = builder.with("fourth", "valueOfFourth").build();
        for(String value : concrete.getAttributes().values())
            System.out.println(value);
    }
}

class ConcreteBuilder{
    private Concrete concrete;

    public ConcreteBuilder(){
        concrete = new Concrete();
    }

    public ConcreteBuilder with(String key, String value){
        concrete.getAttributes().put(key, value);
        return this;
    }
    public Concrete build(){
        return concrete;
    }
}

class Concrete{
    private HashMap<String, String> attributes;

    public Concrete(){
        attributes = new HashMap<>();
    }

    public HashMap<String, String> getAttributes(){
        attributes.put("first", "valueOfFirst");
        attributes.put("second", "valueOfSecond");
        attributes.put("third", "valueOfThird");
        return attributes;
    }
}
公共类演示{
公共静态void main(字符串[]args){
ConcreteBuilder=新的ConcreteBuilder();
混凝土=建筑商。加上(“第四”、“第四个值”)。建筑();
for(字符串值:concrete.getAttributes().values())
系统输出打印项次(值);
}
}
等级混凝土建造师{
私人混凝土;
公共混凝土建造商(){
混凝土=新混凝土();
}
具有(字符串键、字符串值)的公共混凝土生成器{
concrete.getAttributes().put(键,值);
归还这个;
}
公共混凝土建筑(){
返回混凝土;
}
}
等级混凝土{
私有HashMap属性;
公共混凝土(){
attributes=newhashmap();
}
公共HashMap getAttributes(){
属性。放置(“第一”、“第一值”);
属性。put(“second”、“valueOfSecond”);
出售(“第三”、“第三价值”);
返回属性;
}
}
这里的神奇之处在于,您(可能)不再需要所有这些子类。 如果这些子类的行为没有改变,而只是改变了它们的变量,那么使用这样的系统应该没问题。 我强烈建议你阅读Martin Fowler关于这个主题的文章,虽然有好的地方和不好的地方,但我认为这是一个好的地方


我希望这能让你更接近一个答案,祝你好运。:)

我知道这有点晚了,但我希望你能给我一个答案!当时我的主管告诉我要完全避免构建器模式,因为bean需要有getter和setter方法。我很天真,希望实现一个“聪明”的解决方案。
public class NutritionFacts {

    private final int calories;

    public static class Builder<T extends Builder> {

        private int calories = 0;

        public Builder() {}

        public T calories(int val) {
            calories = val;
            return (T) this;
        }

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

    protected NutritionFacts(Builder builder) {
        calories = builder.calories;
    }
}

public class GMOFacts extends NutritionFacts {

    private final boolean hasGMO;

    public static class Builder extends NutritionFacts.Builder<Builder> {

        private boolean hasGMO = false;

        public Builder() {}

        public Builder GMO(boolean val) {
            hasGMO = val;
            return this;
        }

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

    protected GMOFacts(Builder builder) {
        super(builder);
        hasGMO = builder.hasGMO;
    }
}
public abstract BaseClass {
// various fields go here
...
    public abstract Builder<T extends BaseClass, B extends Builder<T,B>> {
    // add chaining methods here
    ...
    public T build() {
        if (isValid()) return new T(this);
        else Throw new IllegalArgumentException("Invalid data passed to builder.");
    }
    }
public BaseClass(Builder builder) {
    // set fields of baseclass here
}
}
class ParentBuilder{
    public ConcreteParent build(){
        ConcreteParent parent = new ConcreteParent();
        parent.setFirst(1);
        parent.setSecond(2);
        parent.setThird(3);
        return parent;
    }
}

class ChildBuilder{
    public ConcreteChild build(ParentBuilder parentBuilder){
        ConcreteParent parent = parentBuilder.build();
        ConcreteChild child = new ConcreteChild();
        child.setFirst(parent.getFirst());
        child.setSecond(parent.getSecond());
        child.setThird(parent.getThird());
        child.setFourth(4); //Child specific value
        child.setFifth(5); //Child specific value
        return child;
    }
}
        public NutritionFacts build() { return new NutritionFacts(this); }
    }

    protected NutritionFacts(Builder builder) {
        calories = builder.calories;
    }
public class Demo {

    public static void main(String[] args) {
        ConcreteBuilder builder = new ConcreteBuilder();
        Concrete concrete = builder.with("fourth", "valueOfFourth").build();
        for(String value : concrete.getAttributes().values())
            System.out.println(value);
    }
}

class ConcreteBuilder{
    private Concrete concrete;

    public ConcreteBuilder(){
        concrete = new Concrete();
    }

    public ConcreteBuilder with(String key, String value){
        concrete.getAttributes().put(key, value);
        return this;
    }
    public Concrete build(){
        return concrete;
    }
}

class Concrete{
    private HashMap<String, String> attributes;

    public Concrete(){
        attributes = new HashMap<>();
    }

    public HashMap<String, String> getAttributes(){
        attributes.put("first", "valueOfFirst");
        attributes.put("second", "valueOfSecond");
        attributes.put("third", "valueOfThird");
        return attributes;
    }
}