Java最佳实践:仅使用静态方法的类

use*_*892 42 java singleton static nio

我有一个应用程序,我有一个名为的类PlausibilityChecker.这个类只有静态方法,比如checkZipcodeFormatcheckMailFormat.我在GUI类中使用它们来检查输入,然后再将它发送到较低层.

这是好习惯吗?我以为我只使用静态方法,所以我不必关心将实例传递给GUI类或者在每个gui类中都有一个不引用gui对象的实例字段.

我注意到这个FilesJava NIO只有静态方法所以我认为这不是那么可怕的错误.

Lui*_*oza 41

我会说你做得对.除此之外,您的实用程序类的一些建议:

  • 确保它没有任何状态.也就是说,除非声明它,否则类中没有字段static final.此外,请确保此字段也是不可变的,例如Strings.
  • 确保它不能是其他类的超类.使类成为final其他程序员无法扩展它.
  • 这个是有争议的,但你可以声明一个无参数的构造函数private,所以没有其他类可以创建你的实用程序类的实例(使用反射或类似的东西会做,但没有必要去保护类).你为什么不这样做?好吧,这是一个奇怪的情况,你需要/需要注入实用程序类的实例,例如通过接口,而不是直接在你的类中使用它.这是一个例子.这种设计很奇怪但可能会发生(如上面的链接所示),但是如果你不能在这种情况下运行,最好的建议就是保留构造函数private.

有很多库提供实用程序类,以帮助程序员完成我们的工作.其中最着名的是Apache Common库集.它是开源的,您可以检查代码,看看他们如何设计这些实用程序类以创建您的.(免责声明:我不工作或支持这些库,我是他们的快乐用户)

重要说明:避免在实用程序类中使用单例.


小智 14

在Java 8中,您现在可以将静态实用程序类更改为具有静态实现的接口.这消除了使类最终并且必须提供私有构造函数的需要.如果您有它(所有接口都是抽象的,使他们不能最终)这是为改变"类"到"接口"和取出最后一句话那么简单.由于接口方法始终是公共的,因此您可以从中删除任何公共范围.如果您有一个私有构造函数,那么也删除它(您无法使用构造函数编译接口,因为它们无法实例化).它的代码更少,看起来更干净.您不必重构已经使用它的任何类.


Zho*_*gYu 5

不要担心子类化或实例化。JDK 中的以下实用程序类可以被子类化或实例化,但这些年来没有人滥用它们。人不是那个愚蠢的。

java.beans.Beans
java.beans.PropertyEditorManager
java.lang.invoke.LambdaMetafactory
java.lang.reflect.Modifier
java.net.URLDecoder                                   ...but not URLEncoder:)
javax.management.DefaultLoaderRepository
javax.management.Query
javax.management.loading.DefaultLoaderRepository
javax.management.relation.RoleStatus
javax.print.ServiceUI
javax.swing.UIManager
javax.swing.plaf.basic.BasicBorders
javax.swing.plaf.basic.BasicGraphicsUtils
javax.swing.plaf.basic.BasicHTML
javax.swing.plaf.basic.BasicIconFactory
javax.swing.plaf.metal.MetalBorders
javax.swing.plaf.metal.MetalIconFactory
javax.swing.text.Utilities
javax.swing.text.html.HTML
Run Code Online (Sandbox Code Playgroud)

但是,作为公共 API,您确实希望取消默认构造函数,否则 javadoc 页面上有一个未记录的构造函数,这很尴尬且令人困惑。对于您自己的内部 API,这无关紧要,没人关心。

但是没有理由抑制子类化。如果有人想继承一个实用程序类,无论出于何种原因,让他。当然,私有构造函数将抑制子类化作为副作用。


在 java8 中,有更多的设计可能性需要考虑——

具有所有静态方法的接口- 这与具有所有静态方法的类一样好。接口和类都不是为此目的而设计的,所以任何一个都可以。但是,不要期望在接口的子类型中继承这些静态方法——接口静态方法是不可继承的。使用 interface 的一个优点是我们不需要禁止默认构造函数出现在 javadoc 中。

具有所有默认方法的接口- 通过继承访问。这很有趣,但通常有问题(继承仅在非静态上下文中有效)。但是在某些 API 设计中它可能是更好的选择,例如这个html builder API。