我喜欢使用Builder模式来实例化具有复杂状态的类的对象,而不是使用太多的构造函数参数。
我可以向Class和每个单独的Method添加一个JavaDoc,但我知道的JavaDoc关键字似乎都不适合记录构建器的特殊性,比如什么设置是强制性的,可选设置的默认值是什么。
如果我为每个单独的方法记录强制性或可选的以及默认值,感觉文档太分散了,无法获得全局图像。如果我只记录最后的build()
方法,告诉它什么时候可以用默认值构建实例,什么时候不能。
这些选择似乎都不令人满意。感觉JavaDoc不太适合构建器模式,而是为遗留的面向对象代码风格设计的;否则我理解得不够好。
我搜索了https://www.oracle.com/technical-resources/articles/java/javadoc-tool.html文档,但找不到使用适当标签记录生成器的答案或指南。
@param
看起来像是一个有效的候选者,可以像builder类本身一样在一个地方记录来自生成器的所有setFoo
、withBar
、addBaz
,但它似乎不适合这种用法。
如何在JavaDoc或其他更合适的工具中正确地记录生成器?
您的第一个假设("I可以向类和每个单独的方法添加JavaDoc,[…]"(已经是错误的。
文档仍然是强制性的,并且应该尽可能靠近来源。JavaDoc注释是源代码的部分,因此不能更接近!
人们告诉你评论是一种;反模式";现在没有线索,或者懒得打字,或者两者兼而有之——当你读到源代码时;反模式";糟糕的是,你会发现它谈论的是解释代码中发生的事情的inline注释,而不是出于文档目的的可外部化注释——所以不是JavaDoc或Doxygen注释(或者如何用其他语言命名相应的工具(。
对于您的问题:构建器类也将像任何其他类一样进行文档化,使用JavaDoc提供的关键字和适当的描述性文本。如果你懒得手动添加这些文本,你可以为JavaDoc编写自己的扩展,并定义自己的关键字,为你生成文本。
或者您创建自己的Annotation
,并在主要描述中引用它。下面的示例同时做了(注释和描述性文本(,让您了解我所说的内容(省略了注释@IsMandatory
的定义(。
但通常,Builder
不会有用于强制属性的方法;相反,这些是Builder
的构造函数的参数。
/**
* <p>{@summary Builder for new instances of
* {@link MyObject}.}</p>
* <p>Attributes whose setter methods are marked with the
* {@link IsMandatory @IsMandatory}
* annotation are – obviously – mandatory. If not set before
* {@link #build()}
* is called, an
* {@link IllegalStateException}
* will be thrown.</p>
* <p>In particular, these are the attributes</p>
* <ul>
* <li>{@link #setName(String) name}</li>
* …
* </ul>
*/
public final class MyObjectBuilder
{
/**
* Creates a new instance of {@code MyObjectBuilder}.
*/
public MyObjectBuilder() {…}
/**
* Creates a new instance of
* {@link MyObject}.
*
* @return The new instance.
* @throws IllegalStateException A mandatory attribute was not yet set.
*/
public final MyObject build() throws IllegalStateException {…}
/**
* <p>{@summary Sets the name for the new instance of
* {@link MyObject}.} It can be any arbitrary string with more than
* one character that is not
* {@linkplain String#isBlank() blank}.</p>
* <p><b>Note:</b> This attribute is mandatory! If missing,
* {@link #build()}
* will throw an
* {@link IllegalStateException}.</p>
*
* @param name The name for the new instance.
* @throws NullPointerException {@code name} is {@code null}.
* @throws IllegalArgumentException {@code name} is the empty string, or
* it is
* {@linkplain String#isBlank() blank}.
*/
@IsMandatory
public final void setName( final String name ) throws NullPointerException, IllegalArgumentException {…}
/**
* Sets the other attribute for the new instance of
* {@link MyObject}.
*
* @param other The other attribute.
*/
public final void setOther( final Object other ) {…}
}
玩得开心!