对实用程序类的一个常见做法是为它们提供一个私有构造函数:
public final class UtilClass {
private UtilClass() {}
...
}
但不幸的是,有些工具不喜欢这个私有构造函数。他们可能会警告说,它从未在类中调用过,它没有被测试覆盖,块中不包含注释,等等。
如果你这样做,很多警告都会消失:
public enum UtilClass {;
...
}
我的问题是:除了对未来开发人员的无尽仇恨之外,Java中没有值的枚举和有私有构造函数的类之间还有什么重要区别?
请注意,我不是在问Java枚举与具有公共静态最终字段的类相比有什么优势?。我不是在决定一个列表应该是一堆常量还是一个枚举,而是在决定是把一堆函数放在一个没有构造函数的类中还是一个没有值的枚举中。
还要注意,我其实并不想这么做。我只是想知道作为一般语言知识的一部分的权衡。
例如,使用枚举会用UtilClass.values()
等无用的方法污染自动完成。还有什么其他不利因素?好处?
将enum
用于实际上不是枚举的东西是丑陋且令人困惑的。我想这已经足够不做了。
"效用类"模式是完全合法的。如果你的工具不喜欢,那就是工具的问题。
一个好处是,您可以绝对保证不会创建任何实例,即使是从类内部创建。
缺点是这超出了枚举的通常意图。然而,我们已经为使用枚举实现的singleton执行了此操作。
Joshua Bloch的"Effective Java"中关于此类singleton的这一部分也适用于实用程序类:
您得到了一个坚定的保证,即除了声明的常量之外,不可能有任何实例。JVM提供了这一保证,您可以依赖它
免责声明:我没有使用过这种模式,也不建议支持或反对它。
实用程序类中的以下模式也提供了不存在实例的坚定保证:
public abstract class Util {
private Util() { throw new Error(); }
... // static methods
}
此外,您没有enum提供的其他不相关的静态方法。
唯一的区别是,您仍然可以在类内部调用构造函数:
public final class UtilityClass {
public static final UtilityClass Instance = new UtilityClass();
private UtilityClass () {}
public static int Foo (int a, int b) {
return a+b;
}
}
但既然你是这个类的设计者,那么破坏你自己的代码契约就没有任何意义了。
一般来说,我读过的大多数软件设计书籍都反对使用静态方法。除非它们真的是实用的方法:从某种意义上说,它们将永远不需要任何状态。即便如此,实现Singleton模式也只是一个小小的努力,这样,当时机成熟时,您就可以为其分配状态:
public final class UtilityClass {
public static final UtilityClass Instance = new UtilityClass();
private UtilityClass () {}
public int Foo (int a, int b) {
return a+b;
}
}
并用UtilityClass.Instance.Foo(2,5);
调用它。稍后在编码过程中执行引入状态转换会更加困难<因此,静态方法更难维护>
实例之所以有用,是因为你可以在很多模式中使用它们,比如策略,如果在某个场合它取决于应该做什么,。。。通过使用static
方法,可以降低方法的动态性,因为Java不支持方法指针(这是有充分理由的)<因此,非静态方法更具动态性和实用性>
此外,一些安全研究人员认为,使用static
修饰符分析代码更困难,因为它们可以从任何地方访问,并且副作用不太可预测(例如在自动安全分析工具中):假设你有一个类没有完全实现,然后你仍然可以分析字段,知道它可以访问哪些方法,从而分析可能的副作用(网络使用、文件IO…)。这可以为每个类别生成一个应该验证的可能危害列表。至少如果我理解我的一位同事的博士论文是正确的<因此,非静态方法允许更多的修饰符分析>
总之:Java是建立在面向对象编程的原则之上的。这意味着"c类世界"由c编译器使用,而"i实例世界"则由i企业/运行时使用。我同意这两个词之间有很多冲突。但static
方法在许多/某些情况下是解决此类冲突的错误。