在什么情况下静态方法是一个好的做法?

我已阅读以下讨论:

私人帮手方法应该是静态的,如果他们可以是静态的 ,
如果所有的方法都没有成员variables,它们应该是静态的

一般人似乎都会接受静态方法,但对此有点怀疑,原因如下:

  1. 他们很难testing。
  2. 他们违反了OO原则。 (一个人说,他们是function,而不是方法。)

最可接受的静态方法是私有静态方法。 但是,为什么静态方法完全存在,在什么情况下它们是被优先采用的呢?

静态方法本身并不难testing。 问题是调用静态方法的其他代码很难testing,因为您不能replace静态方法。

我认为静态方法是好的,无论是私人的还是当他们是“实用”的方法 – 例如做string转义。 当你使用静态方法的时候,你希望能够模拟出或者在testing中replace掉。 工厂方法也是有用的,尽pipedependency injection通常是一种更好的方法 – 再次,它部分取决于你是否希望能够replacetesting中的function。

至于不是“OO” – 不是所有你用OO语言写的所有东西都必须是“纯粹”的OO。 有时候,非OO路线更简单实用,导致代码更简单。 Eric Lippert在这方面有一篇很棒的博客文章,很遗憾我现在找不到。 然而, 这个post里有一个相关的评论。 它讲的是扩展方法而不是静态方法,但原理是一样的。

扩展方法经常被批评为“不足够OOP”。 这在我看来是把车放在马前面。 面向对象编程的目的是为大量软件项目的构build提供指导,这些项目由不需要了解彼此工作内部细节的团队编写,以提高生产力。 C#的目的是成为一种有用的编程语言,使我们的客户能够在我们的平台上高效工作。 很明显,OOP既有用也很受欢迎,所以我们试图在C#中使用OOP风格进行编程。 但是C#的目的不是“做一个OOP语言”。 我们根据是否对客户有用来评估function,而不是基于它们是否严格符合一些抽象的学术理想,这些理念是什么使得语言面向对象。 我们乐于从oo,function性,程序性,必要性,陈述性等方面提出意见,只要我们能够制造出一种有益于客户的一致有用的产品。

我会说静态方法肯定是好的,当他们是function ,即他们没有做任何IO,没有任何内部状态,只用他们的参数来计算他们的返回值。

我也将它扩展到改变参数状态的方法,但是如果这样做是过度的,那么静态方法应该是它主要运行的参数类的一个实例方法。

想一下这个。 在OO编码中,每一个函数调用实际上都是这样的:

method(object this, object arg1, object arg2) ,这是你调用的对象。 所有这一切真的是语法糖。 此外,它允许你清楚地定义variables的范围,因为你有对象variables等

静态方法根本没有“this”参数。 即你传递variables,并可能得到一个结果退出。 1.)是人们避免它们的主要原因,你不能创build一个静态方法的接口(还),所以你不能模拟出静态方法来testing它。

其次,OO是程序function等。静态方法在某些情况下很有意义,但是它们总是可以在一个对象上变成一个方法。

请注意,如果没有黑客,你无法删除它:

 static void Main(string[] args) { } 

启动应用程序的代码必须是可调用的,不需要引用对象。 所以他们给你灵活性,不pipe你select在你的场景中使用它们,都会根据你的要求来判断。

在单例模式给出了太多的灵活性的大多数情况下,静态方法是好的。

例如,采取一个简单的实用工具,例如将一个原始元素提升为一种力量 – 显然你永远不需要有任何多态性。 原始值是静态types的,math运算是明确定义的,不会改变。 这不是像你永远不会得到两个不同的 实现的情况下,不改变他们之间的所有客户端代码之间切换。


(讽刺)

如果只加载一个接口的实现,那么现代JVM在内联小调用上相当不错。 除非你已经对你的代码进行了简介,并且知道把你的工具分配给一个接口是一个开销,否则你没有理由不把你的工具方法变成一个可以根据需要改变的接口 。

静态方法的另一个好scheme是Factory模式的实现,在这种模式下 ,您可以以特定方式构build类的实例。

考虑Calendar类,该类有一组静态getInstance方法,每个方法都返回使用所需时TimeZone和/或Locale或默认值启动的实例。

我认为静态方法的一个确定的情况是当你不能使它们变成dynamic的,因为你不能修改这个类

这是JDK对象的典型特征,也是所有来自外部库的对象,也是原始types

我经常使用静态工厂方法而不是公共构造函数。

我这样做,当我需要一个构造函数,做一些你不希望一个构造函数做的事情。 即从文件或数据库加载设置。

这种方法也提供了根据他们所做的事情命名“构造器”的可能性。 当参数本身不足以确定构造函数中发生了什么时,这是特别有用的。

Sun使用这种方法

 Class.forName("java.lang.Integer"); 

 Boolean.valueOf("true"); 

首先,你不能排除静态方法,人们仍然有使用它的原因。

  1. 一些devise模式是基于静态方法的,例如singleton:

    Config.GetInstance();

  2. 帮助函数,可以说你有一个字节stream,你想要一个函数将其转换成一个hex数字的string。

静态方法有很多用途,这并不意味着有人滥用它(代码审查是人们滥用代码的最佳select)。

Util类可以是静态的。 正如在上面的某个例子中,转义string一样。 问题在于这些utils类执行我们想要嘲笑的函数。 例如,apache commons中的FileUtils类 – 通常情况下,我想模拟文件交互而不必使用真实文件。 如果这是一个实例类,这将是容易的。

重构静态方法要容易得多。 它阻止不必要的引用现场成员,使耦合紧密。 调用代码也更容易理解,因为它明确地传递了它所交互的任何对象。

通常我会避免静态方法,当一个单一的实例将正常工作。 这个单一的实例可以实现一个接口,可以很容易地被模拟。 我不是说永远不会,但我很less使用静力学。 我告诉我的团队,如果他们想要使用静态的话,应该由团队清理。 我的答案几乎从来不是。