类仅具有静态字段和方法是不好的做法吗?


70

我有一个包含静态成员变量和静态方法的类。本质上,它充当通用实用程序类。

只包含静态成员变量和静态方法的类是不好的做法吗?


28
java.lang.Math是带有private构造函数的100%静态方法(无法实例化)。
Asaph,

不确定是否在此论坛中提出了这个问题。但是,仅包含静态字段的类是一种不好的做法吗?我见过很多这样的类,我认为它们不适合OOP。
ka3ak 2012年

@ ka3ak仅具有静态字段的类在此问题的一些答案中得到部分解决。
斯蒂芬·沃特金斯

Answers:


88

不,我一点也不这么认为。糟糕的做法是,使类中充满实例方法,而这些实例方法实际上并不依赖于特定实例。将它们设置为静态会告诉用户确切的用途。此外,您可以通过这种方式避免不必要的实例化。

编辑:事后,总的来说,我认为避免使用语言功能是“很好的理由”,或者因为您认为那是“ Java方式”。我回想起我的第一份工作,当时我有一个充满静态实用程序方法的类,一位高级程序员告诉我,我没有通过将所有方法设为“全局”来充分利用Java的OO功能。6个月后,她不再加入团队。


7
哈-并非我要暗示的意思
-danben

19

只要该类没有内部状态,并且本质上就是所谓的叶子类(实用程序类属于此类),也就是说,它独立于其他类。没事。

Math班是一个典型的例子。


关于叶/实用程序类,您是否有一个不错的链接/文章?
Zoran Pavlovic 2014年

13

听起来很合理。

注意:这样做的类通常只有一个私有的无参数构造函数,以便程序员在尝试创建静态类的实例时,编译器会产生错误。


4
私有默认构造函数还可以防止子类化您的静态类。
David

1
您是否有任何理由要对静态类进行子类化?(想不到...我不是语言专家)
Jason S

4
在这种情况下,防止子类化是“ pro”。可能其他人在您的项目上工作可能会偶然尝试对静态类进行子类化(通过错别字或误解)。通过添加私有默认构造函数,您将通过更严格地强制使用它来为类添加更多含义。
大卫,

1
将班级定为最终班也将防止子班级。
HexAndBugs

9

静态方法不用担心(测试除外)。

通常,静态成员是一个问题。例如,如果您的应用是集群的怎么办?启动时间如何-正在进行哪种初始化?有关这些问题的更多信息,请查看Gilad Bracha的这篇文章


2
+1用于区分静态函数(精细)和静态状态(可疑)
mikera 2012年

3

这是完全合理的。实际上,在C#中,您可以为此专门使用static关键字定义一个类。


3

只是不要被它带走。请注意,java.lang.Math类仅与数学函数有关。例如,您可能还有一个StringUtilities类,其中包含标准API中没有的常见字符串处理函数。但是,例如,如果您的类名为Utilities,则暗示您可能希望将其拆分。


2

还要注意,Java特别引入了静态导入:(http://en.wikipedia.org/wiki/Static_import

静态导入是Java编程语言中引入的一项功能,该功能在类中定义为公共静态的成员(字段和方法)将在Java代码中使用,而无需指定定义字段的类。此功能已在5.0版本的语言中引入。

该功能提供了一种类型安全机制,可将常量包含在代码中,而不必引用最初定义该字段的类。它还有助于弃用创建常量接口的做法:仅定义常量然后编写实现该接口的类的接口,这被认为是对接口的不当使用[1]。

该机制可用于引用类的单个成员:

 import static java.lang.Math.PI;
 import static java.lang.Math.pow;

或类的所有静态成员:

 import static java.lang.Math.*;

我认为这与他的要求有些偏离。静态导入与类是否仅具有静态成员无关。如果有的话,它可以工作。
danben

1
既有很好的信息,又有很好的论据说明为什么要这样做。
Chuck

抱歉,我不同意-我认为这是关于使用静态方法的一种说法,但是它并没有说明具有非要实例化的类。
danben

@danben:对于要实例化的类,静态导入的意义不大(至少对我而言)。对于拥有许多静态方法(如java.lang.Math)的“实用程序类”,这最有意义。你不这样认为吗?
Chuck

可能在这里挑剔,但是当您说在您要实例化的课程上说它们没什么意义时,我同意您的看法。但是,我不同意它们在无法实例化的类上更有意义。
danben

2

尽管我同意这听起来像是一个合理的解决方案(正如其他人已经指出的那样)的观点,但您可能要考虑的一件事是,从设计的角度来看,为什么要有一个仅出于“实用”目的的类。这些功能是整个系统上真正通用的功能,还是与体系结构中某些特定类的对象有关?

只要您考虑了一下,我就认为您的解决方案没有问题。


1

Java SDK中的Collections类仅具有静态成员。

因此,只要您有正当的理由,就可以使用它-这不是一个糟糕的设计


1

实用程序方法通常放在只有静态方法的类中(例如StringUtils。)全局常量也放在他们自己的类中,以便可以由其余代码(public final static属性)导入它们。

两种用法都很常见,并且具有私有的默认构造函数以防止实例化它们。声明类final可以防止尝试覆盖静态方法的错误。

如果static member variables您不是要使用全局常量,则可能需要将访问这些变量的方法放在它们自己的类中。在那种情况下,您能否详细说明这些变量在代码中的作用?



1

根据对面向对象设计的严格解释,应该避免使用实用程序类。

问题是,如果您遵循严格的解释,那么您将需要将您的类强加到某种排序对象中才能完成许多事情。

甚至Java设计人员也创建实用程序类(想到了java.lang.Math)

您的选择是:

double distance = Math.sqrt(x*x + y*y);  //using static utility class

vs:

RootCalculator mySquareRooter = new SquareRootCalculator();
mySquareRooter.setValueToRoot(x*x + y*y);
double distance;
try{
   distance = mySquareRooter.getRoot();
}
catch InvalidParameterException ......yadda yadda yadda.      

即使我们避免使用冗长的方法,我们仍然可能最终得到:

Mathemetician myMathD00d = new Mathemetician()
double distance = myMathD00d.sqrt(...);

在这种情况下,.sqrt()仍然是静态的,那么首先创建对象的意义是什么?

答案是,当您的其他选择是创建某种对实例变量没有用处或使用很少的人工“ Worker”类时,请创建实用程序类。



0

我不会担心包含静态方法的实用程序类。

但是,静态成员本质上是全局数据,应避免使用。如果将它们用于缓存静态方法等的结果,则可能是可接受的;但如果将它们用作“真实”数据,则可能导致各种问题,例如隐藏的依存关系和设置测试的困难。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.