java - 如何在 Java 中实现具有继承性的 Fluent Builder

标签 java inheritance builder fluent fluent-interface

问题

我想创建一个带有fluent builder的类,两者都可以继承和扩展。基类应该有所有公共(public)和必填字段,子类应该有不同的可选字段

下面的简单示例(我能想到的最好、最简单的用例;p)

base: Animal
    name
    age

    static Builder


impl: Snake extends Animal
    length

    static Builder extends Animal.Builder


impl: Spider extends Animal
    numberOfLegs

    static Builder extends Animal.Builder

我想以其中一种方式使用它(最喜欢的是第一种):

Spider elvis = Spider.name("elvis").age(1).numberOfLegs(8).build();
Spider elvis = Spider.builder().name("elvis").age(1).numberOfLegs(8).build();
Spider elvis = new Spider.Builder().name("elvis").age(1).numberOfLegs(8).build();

我要实现的是

  • 此构建器的用户必须提供一些最少的信息(这样系统才能正常工作),否则他将无法构建该对象
  • 所有可选字段都可以在必填字段之后声明,没有特定顺序
  • 我可能需要为 child 添加一些必填字段,但只需更改构建器中调用的第一个方法即可轻松处理
    • 我不想在这些类之外进行任何强制转换(此处:在 Main 中),但我不介意在这段代码中(此处:在 Animal 或 Spider 中)

到目前为止我失败了,如果你能帮我找到解决办法,我将不胜感激:) 还是我应该考虑一种不同的方法?

我使用的最有值(value)的资源

http://blog.crisp.se/2013/10/09/perlundholm/another-builder-pattern-for-java
http://egalluzzo.blogspot.com/2010/06/using-inheritance-with-fluent.html
Generic fluent Builder in Java

到目前为止完成的工作

到目前为止的代码可以在下面找到。有一些我尝试和失败的痕迹,有一些未使用或只是奇怪的东西(最好的例子是 IBuildImpl)。留下这些是为了让您了解我的尝试,但如果您认为这需要适度 - 请告诉我,我会清理它们

基地

package fafafa;

public abstract class Animal<T> {
    String name; //mandatory field, one of many
    Integer age; //mandatory field, one of many

    public String getName() {
        return name;
    }

    @Override
    public String toString() {
        return "Animal{" +
                "name='" + name + '\'' +
                ", age='" + age + '\'' +
                '}';
    }


    interface IName {
        IAge name(String name);
    }

    interface IAge {
        IBuild age(Integer age);
    }

    interface IBuild<T extends Animal<T>> {
        T build();
    }


    public abstract static class Builder<T extends Animal<T>, B extends Builder<T, B>>
            implements IName, IAge, IBuild<T> {
        protected T objectBeingBuilt;

        protected abstract B that();
        protected abstract T createEmptyObject();

        Builder(){
            this.objectBeingBuilt = createEmptyObject();
            System.out.println();
        }

        @Override
        public IAge name(String name) {
            objectBeingBuilt.name = name;
            return that();
        }

        @Override
        public IBuild age(Integer age) {
            objectBeingBuilt.age = age;
            return that();
        }

//        @Override
//        public T build() {
//            return objectBeingBuilt;
//        }
    }


}

实现

package fafafa;

public class Spider extends Animal<Spider> {
    Integer numberOfLegs; //optional field, one of many

    private Spider() {
    }

    public Integer getNumberOfLegs() {
        return numberOfLegs;
    }

    @Override
    public String toString() {
        return "Spider{" +
                "numberOfLegs='" + numberOfLegs + '\'' +
                "} " + super.toString();
    }

//    public static Builder<Spider, Builder> name(String name) {
//        return (Builder) new Builder().name(name);
//    }


    interface INumberOfLegs {
        IBuild numberOfLegs(Integer numberOfLegs);
    }

    interface IBuildImpl extends IBuild<Spider>, INumberOfLegs {
        @Override
        Spider build();
    }


    public static class Builder extends Animal.Builder<Spider, Builder> implements IBuildImpl {

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

        @Override
        protected Spider createEmptyObject() {
            return new Spider();
        }


        public IBuild numberOfLegs(Integer numberOfLegs) {
            objectBeingBuilt.numberOfLegs = numberOfLegs;
            return that();
        }

        public Spider build() {
            return objectBeingBuilt;
        }
    }
}

主要

package fafafa;

public class Main {
    public static void main(String[] args) {
        Spider build = new Spider.Builder().name("elvis")
                .age(1)
                .numberOfLegs(8) //cannot resolve method numberOfLegs
                .build();
        System.out.println(build);
    }
}

最佳答案

看起来像代码中的许多泛型,我试着稍微简化一下。

动物

package come.stackoverflow.builder;

public abstract class Animal {
  private final String name; //mandatory field, one of many
  private final Integer age; //mandatory field, one of many

  Animal(final String name, final Integer age) {this.name = name; this.age = age;}

  public String getName() {return name;}
  public Integer getAge() {return age;}
  @Override public String toString() {return String.format("Animal {name='%s', age='%s'}'", name, age);}

  interface IBuild<T> {
    T build();
  }

  public abstract static class AnimalBuilder<B extends AnimalBuilder, T extends Animal> implements IBuild<T> {
    String name;
    Integer age;

    public B name(final String name) {this.name = name; return (B) this;}
    public B age(final Integer age) {this.age = age; return (B) this;}
  }
}

蜘蛛

package come.stackoverflow.builder;

public class Spider extends Animal {
  private final Integer numberOfLegs; //optional field, one of many

  private Spider(final String name, final Integer age, final Integer numberOfLegs) {super(name, age); this.numberOfLegs = numberOfLegs;}

  public Integer getNumberOfLegs() {return numberOfLegs;}
  @Override public String toString() {return String.format("Spider {numberOfLegs='%s'}, %s", getNumberOfLegs(), super.toString());}

  public static class SpiderBuilder extends AnimalBuilder<SpiderBuilder, Spider> {
    Integer numberOfLegs;
    public SpiderBuilder numberOfLegs(final Integer numberOfLegs) {this.numberOfLegs = numberOfLegs; return this;}
    public Spider build() {return new Spider(name, age, numberOfLegs);}
  }
}

主要测试

import come.stackoverflow.builder.Spider;

public class Main {
    public static void main(String[] args) {
        Spider build = new Spider.SpiderBuilder()
            .name("elvis").numberOfLegs(8).age(1)
            .build();
        System.out.println(build);
    }
}

执行结果: 蜘蛛 {numberOfLegs='8'},动物 {name='elvis', age='1'}'

关于java - 如何在 Java 中实现具有继承性的 Fluent Builder,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41047524/

相关文章:

java - 'stringList[3]' 等字符串的正则表达式

java - 正则表达式和 Java 的问题 : Words may contain only letters and hyphens (-) and must begin with a letter

inheritance - swift 从其基类返回子类

java - java.util.EnumSet<E> 是如何工作的?

c++ - 如何测试B类是否派生自A类?

ruby /生成器 API : create XML without using blocks

java - JAVA中根据列对动态二维数组进行排序

java - android - 带有随机图片的动画

javascript - 递归构建器嵌套问题

iphone - 如何将 Interface Builder 文档版本控制默认设置为 4.2?