一个类只有静态字段和方法是不好的做法吗?

Posted

技术标签:

【中文标题】一个类只有静态字段和方法是不好的做法吗?【英文标题】:Is it bad practice for a class to have only static fields and methods? 【发布时间】:2010-12-28 21:53:33 【问题描述】:

我有一个类,它由静态成员变量和静态方法组成。本质上,它是一个通用的实用程序类。

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

【问题讨论】:

java.lang.Math 是 100% 静态方法,带有 private 构造函数(无法实例化)。 不确定这个问题是否已在此论坛中提出。但是一个类只有静态字段是不是一种不好的做法?我见过很多这样的课程,我认为它们不适合 OOP。 @ka3ak 仅具有静态字段的类在此问题的一些答案中得到了部分解决。 【参考方案1】:

不,我不这么认为。让一个类充满实例方法实际上并不依赖于特定实例是更糟糕的做法。将它们设为静态会告诉用户它们打算如何使用。此外,您可以通过这种方式避免不必要的实例化。

编辑:作为事后的想法,总的来说,我认为避免使用语言特性“只是因为”或者因为您认为这是“Java 的做法”是很好的。我记得我的第一份工作,我有一个充满静态实用方法的类,一位高级程序员告诉我,通过使我的所有方法“全局”,我没有完全利用 Java 的 OO 功能。 6 个月后她不在团队中。

【讨论】:

【参考方案2】:

只要类没有内部状态并且本质上是所谓的叶类(实用程序类属于此类),换句话说,它独立于其他类。没关系。

Math 类就是一个很好的例子。

【讨论】:

你有关于叶子/实用程序类的不错的链接/文章吗?【参考方案3】:

听起来很合理。

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

【讨论】:

私有默认构造函数还可以防止子类化您的静态类。 您是否有任何理由要对静态类进行子类化? (想不出一个……我不是语言大师) 在这种情况下防止子分类是“专业人士”。从事您项目的其他人可能会不小心尝试对您的静态类进行子类化(通过拼写错误或误解)。通过添加私有默认构造函数,您可以通过更严格地执行它的使用方式来为您的类添加更多意义。 将类设为 final 也会阻止子类化。【参考方案4】:

静态方法并不让我担心(测试除外)。

一般来说,静态成员是一个问题。例如,如果您的应用程序是集群的怎么办?启动时间怎么样——正在发生什么样的初始化?要考虑这些问题以及更多问题,请查看 Gilad Bracha 的 this article。

【讨论】:

+1 用于区分静态函数(精细)和静态(可疑)【参考方案5】:

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

【讨论】:

【参考方案6】:

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

【讨论】:

【参考方案7】:

另请注意,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:静态导入对您要实例化的类没有多大意义(至少对我而言)。它对包含大量静态方法(如 java.lang.Math)的“实用程序类”最有意义。你不这么认为吗? 这里可能会吹毛求疵,但我同意你的观点,因为你说它们对你要实例化的类没有多大意义;但是,我不同意它们对无法实例化的类更有意义。【参考方案8】:

虽然我同意这听起来像是一个合理的解决方案的观点(正如其他人已经说过的那样),但您可能需要考虑的一件事是,从设计的角度来看,为什么您有一个仅用于“实用”目的的类.这些功能是否真正在整个系统中通用,或者它们是否真的与您架构中的某些特定类别的对象相关。

只要您考虑到这一点,我认为您的解决方案没有问题。

【讨论】:

【参考方案9】:

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

所以,只要你有适当的理由,你就可以了——这不是一个糟糕的设计

【讨论】:

【参考方案10】:

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

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

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

【讨论】:

【参考方案11】:

这通常是实用程序类的设计方式,这并没有错。著名的例子包括o.a.c.l.StringUtilso.a.c.d.DbUtilso.s.w.b.ServletRequestUtils等。

【讨论】:

【参考方案12】:

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

问题在于,如果您遵循严格的解释,那么您需要将您的类强制转换为某种对象才能完成许多事情。

即使是 Java 设计人员也制作实用程序类(想到 java.lang.Math)

您的选择是:

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

对比:

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() 仍然是静态的,那么首先创建对象有什么意义呢?

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

【讨论】:

【参考方案13】:

此链接http://java.dzone.com/articles/why-static-bad-and-how-avoid 似乎与此处的大多数答案背道而驰。即使它不包含成员变量(即没有状态),静态类仍然是一个坏主意,因为它不能被模拟或扩展(子类化),所以它违背了 OO 的一些原则

【讨论】:

【参考方案14】:

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

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

【讨论】:

【参考方案15】:

来自TSLint’s docs:

来自 Java 风格的 OO 语言的用户可以将他们的实用程序函数包装在一个额外的类中,而不是将它们放在顶层。

最好的方法是使用常量,像这样:

export const Util = 
    print (data: string): void 
        console.log(data)
    

此规则的错误代码示例:

class EmptyClass 

class ConstructorOnly 
  constructor() 
    foo();
  


// Use an object instead:
class StaticOnly 
  static version = 42;
  static hello() 
    console.log('Hello, world!');
  

此规则的正确代码示例:

class EmptyClass extends SuperClass 

class ParameterProperties 
  constructor(public name: string) 


const StaticOnly = 
  version: 42,
  hello() 
    console.log('Hello, world!');
  ,
;

【讨论】:

以上是关于一个类只有静态字段和方法是不好的做法吗?的主要内容,如果未能解决你的问题,请参考以下文章

全局静态类和方法不好吗?

Java 最佳实践:只有静态方法的类

java 中静态内部类字段啥时候初始化?是在外部类加载的时候就初始化吗?

JavaScript:动态扩展原型是一种不好的做法吗?

c#System.Array类的静态方法Sort()可以对一维数组进行从小到大的排序

用私有属性替换类中的每个字段是一种不好的做法吗? [复制]