假设我有一个抽象类(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的类似的东西,很久以来...