建筑商(Joshua Bloch风格)用于抽象类的具体实现



假设我有一个抽象类(basething)。它具有一个必需的参数("必需基础")和一个可选参数("基本可选")。我有一个将其扩展(事物)的具体类。它还具有一个必需的参数("必需")和一个可选参数("可选")。所以类似:

public abstract class BaseThing {
    public static final String DEFAULT_BASE_OPTIONAL = "Default Base Optional";
    private final String baseRequired;
    private String baseOptional = DEFAULT_BASE_OPTIONAL;
    protected BaseThing(final String theBaseRequired) {
        this.baseRequired = theBaseRequired;
    }
    final void setBaseOptional(final String newVal) {
        this.baseOptional = newVal;
    }
    public final void selfDescribe() {
        System.out.println("Base Required: " + baseRequired);
        System.out.println("Base Optional: " + baseOptional);
        selfDescribeHook();
    }
    protected abstract void selfDescribeHook();
}

和:

public final class Thing extends BaseThing {
    public static final String DEFAULT_OPTIONAL = "Default Optional";
private final String required;
    private String optional = DEFAULT_OPTIONAL;
    Thing(final String theRequired, final String theBaseRequired) {
        super(theBaseRequired);
        required = theRequired;
    }
    @Override
    protected void selfDescribeHook() {
        System.out.println("Required: " + required);
        System.out.println("Optional: " + optional);
    }
    void setOptional(final String newVal) {
        optional = newVal;
    }
}

我想为物体的joshua bloch式建筑商提供一个。不过,更一般地,我想让Basthething的具体实施变得容易拥有建筑商,因此我真正想要的(我认为)是一个可以轻松用于制造东西的建筑商,或者是一个造物构造者,或者是一个彼此。

有一种比以下我想出的更好的方法(或者我想出的问题是否存在问题)?

public abstract class BaseThingBuilder<T extends BaseThing> {
    private String baseOptional = BaseThing.DEFAULT_BASE_OPTIONAL;
    public BaseThingBuilder<T> setBaseOptional(final String value) {
        baseOptional = value;
        return this;
    }
    public T build() {
        T t = buildHook();
        t.setBaseOptional(baseOptional);
        return t;
    }
    protected abstract T buildHook();
}

和:

public final class ThingBuilder extends BaseThingBuilder<Thing> {
    private final String baseRequired;
    private final String required;
    private String optional = Thing.DEFAULT_OPTIONAL;
    public ThingBuilder(final String theRequired,
            final String theBaseRequired) {
        required = theRequired;
        baseRequired = theBaseRequired;
    }
    public ThingBuilder setOptional(final String value) {
        optional = value;
        return this;
    }
    protected Thing buildHook() {
        Thing thing = new Thing(required, baseRequired);
        thing.setOptional(optional);
        return thing;
    }
}

可用于以类似方式构建事物对象的

        BaseThingBuilder<Thing> builder = 
                new ThingBuilder("Required!", "Base Required!")
                    .setOptional("Optional!")
                    .setBaseOptional("Base Optional!");
        Thing thing = builder.build();
        thing.selfDescribe();

输出:

Base Required: Base Required!
Base Optional: Base Optional!
Required: Required!
Optional: Optional!

我知道的一个问题,但我认为并不特别重要(尽管可以改进它,那将是很好的选择)是您必须在设置所有基础之前设置所有非基本选项选项:否则会导致语法错误,因为setBaseOptional()返回basethingbuilder而不是thing bubuilder。

预先感谢。

我认为以这种方式思考建筑商不是一个好主意。建筑商的层次结构通常会导致头痛和脆弱的代码。

减少需要写入混凝土构建器中的代码量,并从基本构建器中重复使用逻辑与域紧密相关。开发一般解决方案并不容易。但是,无论如何,让我们尝试一个例子:

public interface Builder<T> {
  T build();
}
public class Person {
  private final String name;
  //the proper way to use a builder is to pass an instance of one to
  //the class that is created using it...
  Person(PersonBuilder builder) {
    this.name = builder.name;
  }
  public String getName(){ return name; }
  public static class PersonBuilder implements Builder<Person> {
    private String name;
    public PersonBuilder name(String name){ this.name = name; return this; }
    public Person build() {
      if(name == null) {
        throw new IllegalArgumentException("Name must be specified");
      }
      return new Person(this);
    }
  }
}

groovy,宝贝!怎么办?也许您想添加一堂课来代表学生。你做什么工作?你会扩大人吗?当然,这是有效的。如何采用更"奇怪的"路线并尝试聚合?是的,您也可以做到这一点...您的选择将对您最终实施建筑商的方式产生影响。假设您坚持传统的道路并扩展人(您应该已经开始问自己,Person成为具体的课程是有意义的吗?如果我使它变得抽象,我真的需要建造者吗?如果课程是抽象的建筑商是抽象的?):

public class Student extends Person {
  private final long id;
  Student(StudentBulder builder) {
    super(builder);
    this.id = builder.id;
  }
  public long getId(){ return id; }
  //no need for generics, this will work:
  public static class StudentBuilder extends PersonBuilder {
    private long id;
    public StudentBuilder id(long id){ this.id = id; return this; }
    public Student build() {
      if(id <= 0) {
        throw new IllegalArgumentException("ID must be specified");
      }
      return new Student(this);
    }
  }
}

好吧,这看起来完全像您想要的!因此,您尝试了:

Person p = new PersonBuilder().name("John Doe").build();
Student s = new StudentBuilder().name("Jane Doe").id(165).build();

看起来很棒!除了它没有编译...第2行有一个错误,并指出The method id(int) is undefined for the type Person.PersonBuilder。问题在于PersonBuilder#name返回PersonBuilder类型的构建器,这不是您想要的。在StudentBuilder中,您实际上希望name的返回类型为StudentBuilder。现在,您想提前思考,并意识到,如果任何东西扩展了StudentBuilder,您希望它完全返回其他东西...这是可行的吗?是的,与仿制药。但是,这很丑陋,并引入了很多复杂性。因此,我拒绝发布说明它的代码,因为担心有人会看到此线程并实际上在其软件中使用它。

您可能会认为重新安排方法可以使用(在调用name之前调用id):new StudentBuilder().id(165).name("Jane Doe").build(),但不会。至少不是没有明确的铸件对Student(Student)new StudentBuilder().id(165).name("Jane Doe").build(),因为在这种情况下,称为PersonBuilder#build,它具有Person的返回类型...这是不可接受的!即使它没有明确的演员,它也应该使您知道必须按某个顺序调用构建器的方法。因为如果您不这样做,某事将无法正常工作...

,如果您继续尝试使它起作用,将会出现更多的问题。即使您确实使它起作用,我认为它也不容易理解,当然也不优雅。当然,请随时证明我错了并在此处发布您的解决方案。

顺便说一句,您还应该问自己什么是摘要建筑商?因为,这听起来像是矛盾的。

最后,我相信这个问题的范围太大了。答案是特定于域的,在没有您的要求的情况下很难提出。请记住,建筑商的一般指南是让他们尽可能简单。

另外,看看一个相关的问题。

据我所知,

BaseThingBuilder<Thing> builder = 
            new ThingBuilder("Required!", "Base Required!")

更改为

BaseThingBuilder builder = 
            new ThingBuilder("Required!", "Base Required!")

其余部分保持不变,包括必须先初始化子类的限制。因此,我真的不认为这需要使用仿制药。也许我缺少一些东西。

我似乎记得Bjarne Stroustrup的类似的东西,很久以来...

相关内容

  • 没有找到相关文章

最新更新