如何标记方法必须?

假设您使用构建器模式创建类名Person,并假设Builder类包含方法body()head()arms() ,当然还有build()并且您认为方法head()build()必须使用这个class级的用户。

我们想以某种方式标记这些方法是强制性的,如果可能的话使用注释。 如果这个类的用户试图构建一个Person实例但是忘了调用这些方法中的任何一个,我们希望得到某种警告 – 来自java编译器,或者来自我们用来构建我们的Eclipse或Maven项目 – 他们中的任何一个都可以。

有可能吗? 你会建议哪种方式?

下面是一个使用不同类型来强制某些部分的示例(它还使您调用方法的顺序成为必需的):

 package test; import test.StepOne.StepThree; import test.StepOne.StepTwo; import test.StepOne.LastStep; public class TestBuilder { public static void main(String[] args) { String person1 = PersonBuilder.newInstance().head("head").body("body").arm("arm").leg("leg").build(); String person2 = PersonBuilder.newInstance().head("head").body("body").arm("arm").build(); } } interface StepOne { // mandatory StepTwo head(String head); interface StepTwo { // mandatory StepThree body(String body); } interface StepThree { // mandatory LastStep arm(String arm); } // all methods in this interface are not mandatory interface LastStep { LastStep leg(String leg); String build(); } } class PersonBuilder implements StepOne, StepTwo, StepThree, LastStep { String head; String body; String arm; String leg; static StepOne newInstance() { return new PersonBuilder(); } private PersonBuilder() { } public StepTwo head(String head) { this.head = head; return this; } public LastStep arm(String arm) { this.arm = arm; return this; } public StepThree body(String body) { this.body = body; return this; } public LastStep leg(String leg) { this.leg = leg; return this; } public String build() { return head + body + arm + leg; } } 

编辑

OP对这个答案留下了深刻的印象,他在博客中完整地写了这篇文章 。 这是对建造者模式的一种巧妙的看法,这里应该引用完整的处理方法。

我相信正确使用构建器模式可以解决您遇到的问题。

我将创建类PersonBuilder ,它将包含方法setBody()setArms()以及每个其他可选参数setter方法。 构建器的构造函数将采用所需的参数。 然后方法build()将返回Person的新实例。

 public class PersonBuilder { private final Head head; private Body body; private Arms arms; public PersonBuilder(Head head) { this.head = head; } public void setBody(Body body) { this.body = body; } public void setArms(Arms arms) { this.arms = arms; } public Person build() { return new Person(head, body, arms); } } 

或者你可以将Head参数传递给方法build()但我更喜欢在构造函数中传递它。

没办法用编译器。

您可以做的是从build()方法抛出运行时exception,该build()器未正确初始化(并且具有在maven测试阶段调用的测试)

但是你也可以使用build(..)接受一个HeadDetails对象。 这样,tou不能在不指定强制参数的情况下调用构建。

为什么不在build()中调用body(),head(),arms() – 如果它确实是强制的并且在build()方法中返回Person?

[编辑]

简短的例子:

 public class Builder { private final String bodyProp; private final String headProp; private final String armsProp; private String hearProps; public Builder(String bodyProp, String headProp, String armsProp) { super(); this.bodyProp = bodyProp; // check preconditions here (eg not null) this.headProp = headProp; this.armsProp = armsProp; } public void addOptionalHair(String hearProps) { this.hearProps = hearProps; } public Person build() { Person person = new Person(); person.setBody(buildBody()); // ... return person; } private Body buildBody() { // do something with bodyProp return new Body(); } public static class Person { public void setBody(Body buildBody) { // ... } } public static class Body { } } 

也许在build()你可以检查是否已经调用了所有必需的方法。 也许Person实例有一些由build()触发的内部健全性检查。

当然,这会检查运行时行为,并且不会像您描述的那样进行静态分析。

是不是可以在Person的构造函数中调用这些方法?