在什么情况下静态方法是一个好习惯?

时间:2022-03-06 00:40:01

I have read the following discussions:

我看过以下讨论:

Should private helper methods be static if they can be static , and
Should all methods be static if their class has no member variables

如果私有辅助方法可以是静态的,那么它们应该是静态的吗?如果它们的类没有成员变量,那么所有方法都应该是静态的

It seems that people in general would accept static methods, but are a little bit skeptical about it, for the following 2 reasons:

似乎人们通常会接受静态方法,但对此有点怀疑,原因如下:

  1. They are hard to test.
  2. 他们很难测试。

  3. They violate the OO principle. (They are functions, not methods, said a person.)
  4. 他们违反了OO原则。 (一个人说,它们是功能,而不是方法。)

And the most acceptable static methods are private static ones. But then why do static methods exist at all, and in what situations they are the first priority to be adopted?

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

11 个解决方案

#1


55  

Static methods aren't hard to test in and of themselves. The problem is that other code calling the static method is hard to test, because you can't replace the static methods.

静态方法本身并不难测试。问题是调用静态方法的其他代码很难测试,因为你无法替换静态方法。

I think static methods are fine either when they're private or when they're "utility" methods - e.g. to do string escaping. The problem comes when you use static methods for things that you want to be able to mock out or otherwise replace within tests. Factory methods can be useful too, although dependency injection is generally a better approach - again, it partly depends on whether you want to be able to replace the functionality in tests.

我认为静态方法既可以是私有的,也可以是“实用”方法 - 例如做字符串转义。当您希望能够在测试中模拟或替换的东西使用静态方法时,问题就出现了。工厂方法也很有用,虽然依赖注入通常是一种更好的方法 - 再次,它部分取决于您是否希望能够替换测试中的功能。

As for not being "OO" - not everything you write in a generally OO language has to be "pure" OO. Sometimes the non-OO route is simply more pragmatic and leads to simpler code. Eric Lippert has a great blog post about this, which unfortunately I can't find right now. However, there's a comment in this post which is relevant. It talks about extension methods rather than static methods, but the principle is the same.

至于不是“OO” - 不是你用一般OO语言写的所有内容都必须是“纯粹的”OO。有时非OO路线更加务实,导致代码更简单。 Eric Lippert有一篇很棒的博客文章,遗憾的是我现在找不到。但是,这篇文章中的评论是相关的。它讨论的是扩展方法而不是静态方法,但原理是相同的。

Extension methods are often criticized as being "not OOP enough". This seems to me to be putting the cart in front of the horse. The purpose of OOP is to provide guidelines for the structuring of large software projects written by teams of people who do not need to know the internal details of each other's work in order to be productive. The purpose of C# is to be a useful programming language that enables our customers to be productive on our platforms. Clearly OOP is both useful and popular, and we've therefore tried to make it easy to program in an OOP style in C#. But the purpose of C# is not "to be an OOP language". We evaluate features based on whether they are useful to our customers, not based on whether they conform strictly to some abstract academic ideal of what makes a language object-oriented. We'll happily take ideas from oo, functional, procedural, imperative, declarative, whatever, so long as we can make a consistent, useful product that benefits our customers.

扩展方法经常被批评为“不够OOP”。在我看来,这是把车放在马前面。 OOP的目的是为大型软件项目的结构提供指导,这些项目由不需要了解彼此工作的内部细节以便提高工作效率的团队编写。 C#的目的是成为一种有用的编程语言,使我们的客户能够在我们的平台上高效工作。很明显,OOP既有用又受欢迎,因此我们试图在C#中以OOP风格进行编程。但C#的目的不是“成为OOP语言”。我们根据它们是否对我们的客户有用来评估特征,而不是基于它们是否完全符合某些语言面向对象的抽象学术理想。我们很乐意从oo,功能,程序,命令,声明等方面提出想法,只要我们能够制造出有益于我们客户的一致,有用的产品。

#2


17  

I'd say that static methods are definitely OK when they are functions, i.e. they don't do any IO, don't have any internal state and only use their parameters to compute their return value.

我会说静态方法在它们是函数时肯定是可以的,即它们不做任何IO,没有任何内部状态,只使用它们的参数来计算它们的返回值。

I'd also extend this to methods that change the state of their parameters, though if this is done excessively, the static method should properly be an instance method of the parameter class that it mainly operates on.

我还将它扩展到改变其参数状态的方法,但是如果这样做过度,静态方法应该是它主要操作的参数类的实例方法。

#3


5  

Think of this for a moment. In OO coding, every single function call actually looks like this:

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

method(object this, object arg1, object arg2) where this is the object you are calling. All it really is is syntax sugar for this. Additionally it allows you to clearly define scope of variables because you have object variables etc.

方法(对象this,object arg1,object arg2)这是你要调用的对象。它真的就是语法糖。此外,它允许您清楚地定义变量的范围,因为您有对象变量等。

Static methods simply don't have a "this" parameter. Ie you pass variables in and possibly get a result back out. 1.) is the main reason people avoid them, you can't create an interface to a static method (yet) so you can't mock out the static method to test it.

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

Secondly OO are procedures functions etc. Static methods make a lot of sense in certain situations, but they can always be made into a method on an object.

其次OO是程序函数等。静态方法在某些情况下很有意义,但它们总是可以成为对象的方法。

Mind you, you couldn't remove this without a hack:

请注意,你不能在没有黑客的情况下删除它:

static void Main(string[] args)
{
}

The code that starts your application MUST be callable WITHOUT a reference to an object. So they give you flexibility, whether you choose to use them in your scenario will be predicated by your requirements.

启动应用程序的代码必须可以调用而不引用对象。因此,无论您选择在您的场景中使用它们,都会为您提供灵活性,这将取决于您的要求。

#4


3  

Static methods are fine in most situations where the singleton pattern gives too much flexibility.

在单例模式提供过多灵活性的大多数情况下,静态方法都很好。

For example, take a simple utility such as raising a primitive to a power - obviously you never need to have any polymorphism in that. Primitive values are of static type and mathematical operations are well defined and don't change. It's not like you'll ever get the situation of having two different implementations an no way of switching between them without rewriting all your client code.

例如,采用一个简单的实用程序,例如将原语提升为幂 - 显然,您根本不需要具有任何多态性。原始值是静态类型,并且数学运算定义良好且不会改变。这并不像你会得到两种不同的实现情况,无法在不重写所有客户端代码的情况下切换它们。


(irony off )

(反讽)

Modern JVMs are pretty good at inlining small calls if only one implementation of an interface is loaded. Unless you have profiled your code and know dispatching your utilities to an interface is an overhead, you've no excuse for not making your utility methods into an interface which can be varied if required.

如果只加载一个接口实现,现代JVM非常擅长内联小调用。除非您已经对代码进行了分析并且知道将实用程序分派给接口是一种开销,否则您没有理由不将实用程序方法变为可以根据需要改变的接口。

#5


2  

Another good scenario for static methods are implementations of the Factory pattern, where you are allowing for instances of a class to be constructed in a specific manner.

静态方法的另一个好方案是Factory模式的实现,您可以在其中以特定方式构造类的实例。

Consider the Calendar class, which has a set of static getInstance methods, each returning instances primed with the desired TimeZone and/or Locale or the default.

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

#6


1  

I think a definite case for static methods is when you cannot make them dynamic, because you cannot modify the class.

我认为静态方法的一个明确情况是当你不能使它们变得动态时,因为你无法修改类。

This is typical for JDK objects, and also all objects coming from external libraries, and also primitive types.

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

#7


1  

I often use static factory methods instead of or in conjunction with public constructors.

我经常使用静态工厂方法代替公共构造函数或与公共构造函数结合使用。

I do this, when i need a constructor that does something you would not expect a constructor to do. I.e. load settings from a file or database.

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

This approach also provides the possibility of naming the "constructors", based on what they do. This is especially useful, when the parameters themselves are not enough to figure out what happens in a constructor.

这种方法还提供了根据它们的作用命名“构造函数”的可能性。当参数本身不足以弄清楚构造函数中发生的情况时,这尤其有用。

Sun uses this approach in

Sun使用这种方法

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

and

Boolean.valueOf("true");

#8


1  

First of all, you can't dismiss static-methods there is a reason people still use it.

首先,你不能忽视静态方法,人们仍然会使用它。

  1. some design patterns are based on static methods, singleton for example:

    一些设计模式基于静态方法,例如:

    Config.GetInstance();

  2. Helper functions, lets say you have a byte-stream and you want a function to convert it into a string of Hex numbers.

    辅助函数,假设您有一个字节流,并且您希望函数将其转换为十六进制数字串。

there are many uses for static-methods, saying that does not mean that some people abuse it too much(Code Review is best option when people abuse code).

静态方法有很多用途,并不是说有些人滥用它太多了(当人们滥用代码时,Code Review是最好的选择)。

#9


1  

Util classes can be OK to be static. As in someone elses example above, with escaping strings. The problem lies when those utils classes perform functions that we would want to mock. For example, the FileUtils class in apache commons - it is often the case that I want to mock file interactions without having to play with real files. If this was an instance class, it would be easy.

Util类可以是静态的。就像在上面的某些例子中一样,使用转义字符串。当这些utils类执行我们想要模拟的函数时,问题就出现了。例如,apache commons中的FileUtils类 - 通常情况下我想模拟文件交互而不必使用真实文件。如果这是一个实例类,那将很容易。

#10


1  

It's much easier to refactor methods that are static. It discourages unnecessary references to field members that make the coupling tight. It's also easier to understand calling code because it explicitly passes any objects it interacts with.

重构静态方法要容易得多。它不鼓励对字段成员进行不必要的引用,使耦合变紧。理解调用代码也更容易,因为它显式传递了它与之交互的任何对象。

#11


0  

Generally I avoid static methods when a single instance will work fine. That single instance can implement an interface and can be mocked easily. I'm not saying never but I rarely use statics. I tell my team if they want to use a static it should be cleared by the team. Almost never is my answer.

通常,当单个实例工作正常时,我会避免使用静态方法。该单个实例可以实现一个接口,并且可以轻松地进行模拟。我不是说永远不会,但我很少使用静力学。我告诉我的团队他们是否想要使用静态,应该由团队清除。几乎从来不是我的答案。

#1


55  

Static methods aren't hard to test in and of themselves. The problem is that other code calling the static method is hard to test, because you can't replace the static methods.

静态方法本身并不难测试。问题是调用静态方法的其他代码很难测试,因为你无法替换静态方法。

I think static methods are fine either when they're private or when they're "utility" methods - e.g. to do string escaping. The problem comes when you use static methods for things that you want to be able to mock out or otherwise replace within tests. Factory methods can be useful too, although dependency injection is generally a better approach - again, it partly depends on whether you want to be able to replace the functionality in tests.

我认为静态方法既可以是私有的,也可以是“实用”方法 - 例如做字符串转义。当您希望能够在测试中模拟或替换的东西使用静态方法时,问题就出现了。工厂方法也很有用,虽然依赖注入通常是一种更好的方法 - 再次,它部分取决于您是否希望能够替换测试中的功能。

As for not being "OO" - not everything you write in a generally OO language has to be "pure" OO. Sometimes the non-OO route is simply more pragmatic and leads to simpler code. Eric Lippert has a great blog post about this, which unfortunately I can't find right now. However, there's a comment in this post which is relevant. It talks about extension methods rather than static methods, but the principle is the same.

至于不是“OO” - 不是你用一般OO语言写的所有内容都必须是“纯粹的”OO。有时非OO路线更加务实,导致代码更简单。 Eric Lippert有一篇很棒的博客文章,遗憾的是我现在找不到。但是,这篇文章中的评论是相关的。它讨论的是扩展方法而不是静态方法,但原理是相同的。

Extension methods are often criticized as being "not OOP enough". This seems to me to be putting the cart in front of the horse. The purpose of OOP is to provide guidelines for the structuring of large software projects written by teams of people who do not need to know the internal details of each other's work in order to be productive. The purpose of C# is to be a useful programming language that enables our customers to be productive on our platforms. Clearly OOP is both useful and popular, and we've therefore tried to make it easy to program in an OOP style in C#. But the purpose of C# is not "to be an OOP language". We evaluate features based on whether they are useful to our customers, not based on whether they conform strictly to some abstract academic ideal of what makes a language object-oriented. We'll happily take ideas from oo, functional, procedural, imperative, declarative, whatever, so long as we can make a consistent, useful product that benefits our customers.

扩展方法经常被批评为“不够OOP”。在我看来,这是把车放在马前面。 OOP的目的是为大型软件项目的结构提供指导,这些项目由不需要了解彼此工作的内部细节以便提高工作效率的团队编写。 C#的目的是成为一种有用的编程语言,使我们的客户能够在我们的平台上高效工作。很明显,OOP既有用又受欢迎,因此我们试图在C#中以OOP风格进行编程。但C#的目的不是“成为OOP语言”。我们根据它们是否对我们的客户有用来评估特征,而不是基于它们是否完全符合某些语言面向对象的抽象学术理想。我们很乐意从oo,功能,程序,命令,声明等方面提出想法,只要我们能够制造出有益于我们客户的一致,有用的产品。

#2


17  

I'd say that static methods are definitely OK when they are functions, i.e. they don't do any IO, don't have any internal state and only use their parameters to compute their return value.

我会说静态方法在它们是函数时肯定是可以的,即它们不做任何IO,没有任何内部状态,只使用它们的参数来计算它们的返回值。

I'd also extend this to methods that change the state of their parameters, though if this is done excessively, the static method should properly be an instance method of the parameter class that it mainly operates on.

我还将它扩展到改变其参数状态的方法,但是如果这样做过度,静态方法应该是它主要操作的参数类的实例方法。

#3


5  

Think of this for a moment. In OO coding, every single function call actually looks like this:

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

method(object this, object arg1, object arg2) where this is the object you are calling. All it really is is syntax sugar for this. Additionally it allows you to clearly define scope of variables because you have object variables etc.

方法(对象this,object arg1,object arg2)这是你要调用的对象。它真的就是语法糖。此外,它允许您清楚地定义变量的范围,因为您有对象变量等。

Static methods simply don't have a "this" parameter. Ie you pass variables in and possibly get a result back out. 1.) is the main reason people avoid them, you can't create an interface to a static method (yet) so you can't mock out the static method to test it.

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

Secondly OO are procedures functions etc. Static methods make a lot of sense in certain situations, but they can always be made into a method on an object.

其次OO是程序函数等。静态方法在某些情况下很有意义,但它们总是可以成为对象的方法。

Mind you, you couldn't remove this without a hack:

请注意,你不能在没有黑客的情况下删除它:

static void Main(string[] args)
{
}

The code that starts your application MUST be callable WITHOUT a reference to an object. So they give you flexibility, whether you choose to use them in your scenario will be predicated by your requirements.

启动应用程序的代码必须可以调用而不引用对象。因此,无论您选择在您的场景中使用它们,都会为您提供灵活性,这将取决于您的要求。

#4


3  

Static methods are fine in most situations where the singleton pattern gives too much flexibility.

在单例模式提供过多灵活性的大多数情况下,静态方法都很好。

For example, take a simple utility such as raising a primitive to a power - obviously you never need to have any polymorphism in that. Primitive values are of static type and mathematical operations are well defined and don't change. It's not like you'll ever get the situation of having two different implementations an no way of switching between them without rewriting all your client code.

例如,采用一个简单的实用程序,例如将原语提升为幂 - 显然,您根本不需要具有任何多态性。原始值是静态类型,并且数学运算定义良好且不会改变。这并不像你会得到两种不同的实现情况,无法在不重写所有客户端代码的情况下切换它们。


(irony off )

(反讽)

Modern JVMs are pretty good at inlining small calls if only one implementation of an interface is loaded. Unless you have profiled your code and know dispatching your utilities to an interface is an overhead, you've no excuse for not making your utility methods into an interface which can be varied if required.

如果只加载一个接口实现,现代JVM非常擅长内联小调用。除非您已经对代码进行了分析并且知道将实用程序分派给接口是一种开销,否则您没有理由不将实用程序方法变为可以根据需要改变的接口。

#5


2  

Another good scenario for static methods are implementations of the Factory pattern, where you are allowing for instances of a class to be constructed in a specific manner.

静态方法的另一个好方案是Factory模式的实现,您可以在其中以特定方式构造类的实例。

Consider the Calendar class, which has a set of static getInstance methods, each returning instances primed with the desired TimeZone and/or Locale or the default.

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

#6


1  

I think a definite case for static methods is when you cannot make them dynamic, because you cannot modify the class.

我认为静态方法的一个明确情况是当你不能使它们变得动态时,因为你无法修改类。

This is typical for JDK objects, and also all objects coming from external libraries, and also primitive types.

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

#7


1  

I often use static factory methods instead of or in conjunction with public constructors.

我经常使用静态工厂方法代替公共构造函数或与公共构造函数结合使用。

I do this, when i need a constructor that does something you would not expect a constructor to do. I.e. load settings from a file or database.

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

This approach also provides the possibility of naming the "constructors", based on what they do. This is especially useful, when the parameters themselves are not enough to figure out what happens in a constructor.

这种方法还提供了根据它们的作用命名“构造函数”的可能性。当参数本身不足以弄清楚构造函数中发生的情况时,这尤其有用。

Sun uses this approach in

Sun使用这种方法

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

and

Boolean.valueOf("true");

#8


1  

First of all, you can't dismiss static-methods there is a reason people still use it.

首先,你不能忽视静态方法,人们仍然会使用它。

  1. some design patterns are based on static methods, singleton for example:

    一些设计模式基于静态方法,例如:

    Config.GetInstance();

  2. Helper functions, lets say you have a byte-stream and you want a function to convert it into a string of Hex numbers.

    辅助函数,假设您有一个字节流,并且您希望函数将其转换为十六进制数字串。

there are many uses for static-methods, saying that does not mean that some people abuse it too much(Code Review is best option when people abuse code).

静态方法有很多用途,并不是说有些人滥用它太多了(当人们滥用代码时,Code Review是最好的选择)。

#9


1  

Util classes can be OK to be static. As in someone elses example above, with escaping strings. The problem lies when those utils classes perform functions that we would want to mock. For example, the FileUtils class in apache commons - it is often the case that I want to mock file interactions without having to play with real files. If this was an instance class, it would be easy.

Util类可以是静态的。就像在上面的某些例子中一样,使用转义字符串。当这些utils类执行我们想要模拟的函数时,问题就出现了。例如,apache commons中的FileUtils类 - 通常情况下我想模拟文件交互而不必使用真实文件。如果这是一个实例类,那将很容易。

#10


1  

It's much easier to refactor methods that are static. It discourages unnecessary references to field members that make the coupling tight. It's also easier to understand calling code because it explicitly passes any objects it interacts with.

重构静态方法要容易得多。它不鼓励对字段成员进行不必要的引用,使耦合变紧。理解调用代码也更容易,因为它显式传递了它与之交互的任何对象。

#11


0  

Generally I avoid static methods when a single instance will work fine. That single instance can implement an interface and can be mocked easily. I'm not saying never but I rarely use statics. I tell my team if they want to use a static it should be cleared by the team. Almost never is my answer.

通常,当单个实例工作正常时,我会避免使用静态方法。该单个实例可以实现一个接口,并且可以轻松地进行模拟。我不是说永远不会,但我很少使用静力学。我告诉我的团队他们是否想要使用静态,应该由团队清除。几乎从来不是我的答案。