我已阅读以下讨论:
如果可以是静态的,那么私有辅助方法是否应该是静态的? 和
如果类没有成员变量,是否应该使所有方法都是静态的?
总体而言,人们似乎会接受静态方法,但对其持怀疑态度,原因如下:
- 它们很难测试。
- 它们违反了面向对象的原则。(一位人士说,它们是函数,而不是方法。)
最可接受的静态方法是私有静态方法。但那么为什么静态方法存在呢?在什么情况下它们是首选的?
我已阅读以下讨论:
如果可以是静态的,那么私有辅助方法是否应该是静态的? 和
如果类没有成员变量,是否应该使所有方法都是静态的?
总体而言,人们似乎会接受静态方法,但对其持怀疑态度,原因如下:
最可接受的静态方法是私有静态方法。但那么为什么静态方法存在呢?在什么情况下它们是首选的?
静态方法本身并不难测试。问题在于调用静态方法的其他代码很难测试,因为你无法替换静态方法。
我认为当静态方法是私有的或是“工具”方法(例如执行字符串转义)时,使用它们没什么问题。当你在测试中想要mock out或者以其他方式替换静态方法时,问题就出现了。工厂方法也可能有用,虽然依赖注入通常是更好的方法 - 这部分取决于您是否希望在测试中能够替换功能。
至于不符合“面向对象”的问题- 您在通常使用面向对象语言编写的所有内容都不必是“纯粹”的面向对象。有时候非面向对象的路线只是更实用,并且会导致更简单的代码。Eric Lippert在他的一篇非常好的博客文章中探讨了这个问题,但很遗憾我现在找不到它了。但是,在此帖子中有一条评论与此相关。它谈论的是扩展方法而不是静态方法,但原则是相同的。
扩展方法经常被批评为“不够面向对象”。这对我来说似乎是本末倒置。面向对象的目的是提供指导大型软件项目结构的准则,由一组不需要知道彼此工作内部细节就可以高效工作的人员编写。C#的目的是成为使我们的客户在我们的平台上能够提高生产力的有用的编程语言。显然,面向对象是有用和流行的,因此我们试图让在C#中以面向对象风格编程变得容易。但是,C#的目的不是“成为面向对象的语言”。我们根据它们是否对我们的客户有用来评估功能,而不是基于它们是否严格符合某些抽象。
学术理想是什么让一门语言成为面向对象的语言。我们欣然接受oo、函数式、过程式、命令式、声明式等任何思想,只要我们能够制作出一款一致且有用的产品,使我们的客户受益。
我认为静态方法在它们是函数时绝对没问题,也就是说,它们不执行任何IO,没有任何内部状态,并且只使用它们的参数计算返回值。
如果一个静态方法改变它的参数状态,我也会把它归类到静态方法。不过,如果这样做过度,那么这个静态方法应该是主要操作参数类的实例方法。
想一想。在面向对象编程中,每个函数调用实际上看起来像这样:
method(object this, object arg1, object arg2)
这里的this是你正在调用的对象。它只不过是语法糖而已。此外,它允许你清晰地定义变量的作用域,因为你有对象变量等。
静态方法根本没有“this”参数。也就是说,你传入变量,可能会得到一个返回结果。首先,人们避免使用它的主要原因是你无法创建一个指向静态方法的接口(尚未),因此你无法模拟静态方法以进行测试。
其次,面向对象是过程函数等。在某些情况下,静态方法非常有意义,但它们总是可以转换为对象的方法。
请注意,如果没有hack,你不能删除this:
static void Main(string[] args)
{
}
启动应用程序的代码必须可调用而不需要对象引用。因此,它们为您提供了灵活性,是否选择在您的情况下使用它们将取决于您的要求。
我认为静态方法的明确用例是当你无法使它们动态,因为你无法修改类时。
这在JDK对象、来自外部库的所有对象以及原始类型中很常见。
我经常使用静态工厂方法来代替或与公共构造函数一起使用。
当我需要一个构造函数执行某些你不希望构造函数执行的操作时,我会这样做。例如从文件或数据库中加载设置。
这种方法还可以根据它们的功能命名“构造函数”,这在参数本身无法解释构造函数的情况下特别有用。
Sun公司在其
Class.forName("java.lang.Integer");
Boolean.valueOf("true");
Util类可以是静态的。就像上面某个人的示例中转义字符串一样。问题在于当这些utils类执行我们想要模拟的函数时。例如,Apache Commons中的FileUtils类 - 经常出现我想要模拟文件交互而不必使用真实文件的情况。如果这是一个实例类,那么这将很容易。
重构静态方法要容易得多。它会阻止对使耦合紧密的字段成员的不必要引用。同时,调用代码更容易理解,因为它明确地传递了与之交互的任何对象。
首先,你不能忽略静态方法,人们仍然使用它是有原因的。
一些设计模式基于静态方法,例如单例:
Config.GetInstance();
辅助函数,比如说你有一个字节流,想要一个函数将其转换成十六进制数字的字符串。
静态方法有很多用途,但这并不意味着有些人滥用它(当人们滥用代码时,最好的选择是进行代码审查)。