当前位置: 首页 > 知识库问答 >
问题:

构建器模式和继承

禄星腾
2023-03-14
public class Rabbit
{
    public String sex;
    public String name;

    public Rabbit(Builder builder)
    {
        sex = builder.sex;
        name = builder.name;
    }

    public static class Builder
    {
        protected String sex;
        protected String name;

        public Builder() { }

        public Builder sex(String sex)
        {
            this.sex = sex;
            return this;
        }

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

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

public class Lop extends Rabbit
{
    public float earLength;
    public String furColour;

    public Lop(LopBuilder builder)
    {
        super(builder);
        this.earLength = builder.earLength;
        this.furColour = builder.furColour;
    }

    public static class LopBuilder extends Rabbit.Builder
    {
        protected float earLength;
        protected String furColour;

        public LopBuilder() { }

        public Builder earLength(float length)
        {
            this.earLength = length;
            return this;
        }

        public Builder furColour(String colour)
        {
            this.furColour = colour;
            return this;
        }

        public Lop build()
        {
            return new Lop(this);
        }
    }
}
Lop lop = new Lop.LopBuilder().furColour("Gray").name("Rabbit").earLength(4.6f);

由于无法解析最后一个链接调用,Builder未定义EarLength方法,因此此调用将不会编译。所以这种方式要求所有调用都以特定的顺序链接起来,这是非常不切实际的,特别是对于一个深度层次结构树。

现在,在我寻找答案的过程中,我遇到了一个Java Builder类的子类,它建议使用奇怪的递归泛型模式。但是,由于我的层次结构不包含一个抽象类,所以这个解决方案对我不起作用。但是这种方法依赖于抽象和多态性来发挥作用,这就是为什么我不相信我能使它适应我的需要。

我目前使用的一种方法是重写层次结构中超类builder的所有方法,并简单地执行以下操作:

public ConcreteBuilder someOverridenMethod(Object someParameter)
{
    super(someParameter);
    return this;
}

共有1个答案

须新
2023-03-14

对于递归绑定,这当然是可能的,但是子类型构建器也需要是泛型的,并且您需要一些临时的抽象类。它有点麻烦,但仍然比非泛型版本容易。

/**
 * Extend this for Mammal subtype builders.
 */
abstract class GenericMammalBuilder<B extends GenericMammalBuilder<B>> {
    String sex;
    String name;

    B sex(String sex) {
        this.sex = sex;
        return self();
    }

    B name(String name) {
        this.name = name;
        return self();
    }

    abstract Mammal build();

    @SuppressWarnings("unchecked")
    final B self() {
        return (B) this;
    }
}

/**
 * Use this to actually build new Mammal instances.
 */
final class MammalBuilder extends GenericMammalBuilder<MammalBuilder> {
    @Override
    Mammal build() {
        return new Mammal(this);
    }
}

/**
 * Extend this for Rabbit subtype builders, e.g. LopBuilder.
 */
abstract class GenericRabbitBuilder<B extends GenericRabbitBuilder<B>>
        extends GenericMammalBuilder<B> {
    Color furColor;

    B furColor(Color furColor) {
        this.furColor = furColor;
        return self();
    }

    @Override
    abstract Rabbit build();
}

/**
 * Use this to actually build new Rabbit instances.
 */
final class RabbitBuilder extends GenericRabbitBuilder<RabbitBuilder> {
    @Override
    Rabbit build() {
        return new Rabbit(this);
    }
}

有一种方法可以避免“具体的”叶类,如果我们有:

class MammalBuilder<B extends MammalBuilder<B>> {
    ...
}
class RabbitBuilder<B extends RabbitBuilder<B>>
        extends MammalBuilder<B> {
    ...
}

然后需要创建带有菱形的新实例,并在引用类型中使用通配符:

static RabbitBuilder<?> builder() {
    return new RabbitBuilder<>();
}
@SuppressWarnings("unchecked")
final B self() {
    return (B) this;
}

有一种方法可以避免这种未经检查的强制转换,即使方法抽象:

abstract B self();

然后在leaf子类中重写它:

@Override
RabbitBuilder self() { return this; }

这样做的问题是,尽管它的类型安全度更高,但子类可以返回this以外的东西。基本上,无论哪种方法,子类都有可能做错一些事情,所以我看不出有什么理由更喜欢这两种方法中的一种而不是另一种。

 类似资料:
  • 我需要在没有静态嵌套类的情况下实现Builder模式。如果我有遗传,最好的方法是什么?让我们想象一下我有下面的课。 是创建一个Builder类来负责设置PassengerCar和Truck的值更好,还是我们需要另外三个类,CarBuilder,PassengerCarBuilder extends CarBuilder和TruckBuilder extends CarBuilder?

  • 问题内容: 我的对象层次结构随着继承树的加深而增加了复杂性。这些都不是抽象的,因此,它们的所有实例都或多或少地达到了目的。 由于参数数量很多,我想使用“构建器模式”来设置属性,而不是对多个构造函数进行编码。由于我需要适应所有排列,因此继承树中的叶类将具有伸缩构造函数。 当我在设计过程中遇到一些问题时,我已经浏览了这里的答案。首先,让我给您一个简单的,简短的示例来说明问题。 现在我们有一些代码可以继

  • 问题内容: 我已经使用具有继承性的Java绑定搜索了json模式,并且所有搜索都导致我使用“ allOf”。 使用allOf可能会解决我的问题,但我想知道json模式中是否有可以使用的构造,该构造将生成具有真实Java继承“ B扩展A”的Java代码- 而不是在B内插入A的所有属性? 我想知道这是否被支持/可行,或者我只是在做梦。如果不支持,我很想知道原因。 问题答案: 好吧,我是两者的作者: 当

  • 本文向大家介绍设计模式构建器模式/Java 实现,包括了设计模式构建器模式/Java 实现的使用技巧和注意事项,需要的朋友参考一下 示例 通过Builder模式,您可以以易于阅读的方式创建具有许多可选变量的类的实例。 考虑以下代码: 如果所有参数都是必需的,那么一切都很好。如果有更多的变量和/或其中一些是可选的怎么办?您不想使用必需参数和可选参数的每种可能的组合来创建大量的构造函数,因为它变得难以

  • 问题内容: 到目前为止,我使用了构建器模式的以下实现(与此处描述的实现相反): 这在我遇到的大多数情况下都很有效,在这种情况下,我需要使用各种必需/必需和可选参数来构建一个复杂的对象。但是,最近我一直在努力了解当所有参数都是必需的(或者至少绝大多数是强制性的)时,模式有什么好处。 解决此问题的一种方法是在逻辑上将传递给它们自己的类的参数分组,以减少传递给构建器构造函数的参数数量。 例如,代替: 分

  • 问题内容: 我使用ektorp连接到CouchDB。 构建ektorp 实例的方法是使用构建器模式: 我对Spring比较陌生。请为我提供有关如何在上下文中配置以便通过进行创建的建议。 一种方法是使用。还有其他选择吗? 问题答案: 您可以尝试实现接口: 并添加到配置以下bean定义: 然后,您可以将此bean注入另一个bean,它将作为实例进行解析。