生成器模式和继承 [英] Builder Pattern and Inheritance

查看:151
本文介绍了生成器模式和继承的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个对象层次结构,随着继承树的加深,复杂度增加。这些都不是抽象的,因此,他们的所有实例都服务于或多或少的复杂目的。



由于参数数量相当高,我想使用Builder Pattern来设置属性,而不是编写几个构造函数。当我需要满足所有排列时,我的继承树中的叶子类将具有伸缩构造函数。



当我在设计中遇到一些问题时,我已经浏览了一个答案。首先,让我给你一个简单的浅层例子来说明问题。

  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;
返回这个;
}

public Builder名称(String name)
{
this.name = name;
返回这个;
}

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;
返回这个;
}

public Builder furColour(String color)
{
this.furColour = color;
返回这个;
}

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

现在我们有一些代码继续,影像我想建立一个 Lop

  Lop lop = new Lop.LopBuilder()。furColour(Gray)。name(Rabbit)。earLength(4.6f); 

此调用将无法编译,因为最后一个链接的调用无法解析, Builder 没有定义方法 earLength 。所以这种方式要求所有的呼叫都以特定的顺序链接起来,这是非常不切实际的,特别是使用深层次的树。



现在,在我寻找答案的过程中发现了对Java Builder类进行子类化,建议使用好奇的递归通用模式。然而,由于我的层次结构不包含抽象类,所以这个解决方案对我来说是不行的。但是,该方法依赖于抽象和多态来进行功能,这就是为什么我不相信我可以适应我的需要。



我目前已经解决的一个方法是覆盖层次结构中超类 Builder 的所有方法,只需执行以下操作:

  public ConcreteBuilder someOverridenMethod(Object someParameter)
{
super(someParameter);
返回这个;
}

使用这种方法我可以保证我被返回一个可以发行链的实例打电话。虽然这并不像Telescoping反模式那么糟糕,但是它是一个接近的秒,我认为它有点黑客。



是否有另一个解决方案我的问题我不知道吗优选地,与设计图案一致的解决方案。谢谢!

解决方案

这是肯定可以用递归泛型,但你需要将通用类型全部传递下来。语法有点麻烦,但你一定可以这样做。

 抽象类GenericMammalBuilder //将此扩展为
< ; B扩展GenericMammalBuilder< B>> {// Mammal subtype builders

String sex;
字符串名称;

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

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

final class MammalBuilder //使用this to
extends GenericMammalBuilder< MammalBuilder> {//构建新的哺乳动物实例
Mammal build(){
return new Mammal(this);
}
}

抽象类GenericRabbitBuilder //将此扩展为
< B扩展GenericRabbitBuilder< B>> // Rabbit子类型构建器
扩展GenericMammalBuilder< B> {//例如LopBuilder

颜色颜色;

B颜色(颜色){
this.color = color;
return(B)this;
}
}

final class RabbitBuilder //使用这个来构建
扩展GenericRabbitBuilder< RabbitBuilder> {//新的兔子实例
Rabbit build(){
return new Rabbit(this);
}
}

递归泛型的问题是参数必须参数化子类型IE如果您有:

 类A< T扩展A&T;> {} 

class B< T extends B< T>延伸A< T> {}

类C扩展B< C> {}

您可以执行 new C(); 而不是新的B< B>(); 。 (错误地,你也可以做新的B< C>(); 。)



所以你需要一些一种临时具体课。这是一个选择你自己的恶意场景IMO。


I have an object hierarchy that increases in complexity as the inheritance tree deepens. None of these are abstract, hence, all of their instances serve a, more or less sophisticated, purpose.

As the number of parameters is quite high, I would want to use the Builder Pattern to set properties rather than code several constructors. As I need to cater to all permutations, leaf classes in my inheritance tree would have telescoping constructors.

I have browsed for an answer here when I hit some problems during my design. First of, let me give you a simple, shallow example to illustrate the problem.

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);
        }
    }
}

Now that we have some code to go on, imaging I want to build a Lop:

Lop lop = new Lop.LopBuilder().furColour("Gray").name("Rabbit").earLength(4.6f);

This call will not compile as the last chained call cannot be resolved, Builder not defining the method earLength. So this way requires that all calls be chained in a specific order which is very impractical, especially with a deep hierarchy tree.

Now, during my search for an answer, I came across Subclassing a Java Builder class which suggests using the Curiously Recursive Generic Pattern. However, as my hierarchy does not contain an abstract class, this solution will not work for me. But the approach relies on abstraction and polymorphism to function which is why I don't believe I can adapt it to my needs.

An approach I have currently settled with is to override all methods of the superclass Builder in the hierarchy and simply do the following:

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

With this approach I can assure I am being returned an instance I can issue chain calls on. While this is not as worse as the Telescoping Anti-pattern, it is a close second and I consider it a bit "hacky".

Is there another solution to my problem that I am not aware of? Preferably a solution consistent with the design pattern. Thank you!

解决方案

This is certainly possible with the recursive generic but you need to be passing the generic type all way down. The syntax is a little cumbersome but you can certainly do it.

abstract class GenericMammalBuilder     // extend this for
<B extends GenericMammalBuilder<B>> {   // Mammal subtype builders

     String sex;
     String name;

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

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

final class MammalBuilder                       // use this to
extends GenericMammalBuilder<MammalBuilder> {   // build new Mammal instances
    Mammal build() {
        return new Mammal(this);
    }
}

abstract class GenericRabbitBuilder   // extend this for
<B extends GenericRabbitBuilder<B>>   // Rabbit subtype builders
extends GenericMammalBuilder<B> {     // e.g. LopBuilder

    Color color;

    B ofColor(Color color) {
        this.color = color;
        return (B)this;
    }
}

final class RabbitBuilder                       // use this to build
extends GenericRabbitBuilder<RabbitBuilder> {   // new Rabbit instances
    Rabbit build() {
        return new Rabbit(this);
    }
}

The problem with the recursive generic is the parameter must be a parameterized subtype IE if you have:

class A<T extends A<T>> {}

class B<T extends B<T>> extends A<T> {}

class C extends B<C> {}

You can do new C(); but not new B<B>();. (Erroneously, you can also do new B<C>();.)

So you do need some kind of an "interim concrete" class. This is sortof a choose your own evil scenario IMO.

这篇关于生成器模式和继承的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆