在啥情况下静态方法是一个好习惯?
Posted
技术标签:
【中文标题】在啥情况下静态方法是一个好习惯?【英文标题】:In what situations is static method a good practice?在什么情况下静态方法是一个好习惯? 【发布时间】:2010-12-04 13:26:48 【问题描述】:我已阅读以下讨论:
Should private helper methods be static if they can be static 和Should all methods be static if their class has no member variables
似乎人们普遍会接受静态方法,但对此有点怀疑,原因如下:
-
它们很难测试。
它们违反了OO原则。 (他们
是函数,而不是方法,表示
人。)
最可接受的静态方法是私有静态。但是为什么静态方法存在,在什么情况下它们是优先采用的呢?
【问题讨论】:
这个讨论也很有用:在 Java 中何时不使用 static 关键字 ***.com/questions/1766715/… 【参考方案1】:静态方法本身并不难测试。问题是其他代码调用静态方法很难测试,因为你不能替换静态方法。
我认为静态方法在它们是私有时都很好或当它们是“实用程序”方法时 - 例如进行字符串转义。当您将静态方法用于您希望能够在测试中模拟或以其他方式替换的事物时,就会出现问题。工厂方法也可以有用,尽管依赖注入通常是一种更好的方法 - 同样,它部分取决于您是否希望能够替换测试中的功能。
至于不是“OO”——并不是你用一般 OO 语言编写的所有东西都必须是“纯”OO。有时,非 OO 路线更实用,并导致更简单的代码。 Eric Lippert 有一篇很棒的博客文章,遗憾的是我现在找不到。但是,this post 中有一条相关的评论。讲的是扩展方法而不是静态方法,但原理是一样的。
扩展方法经常受到批评 作为“不够OOP”。这似乎 让我把车放在前面 马的。 OOP 的目的是 为结构提供指导 的大型软件项目由 不需要的人的团队 了解每个人的内部细节 为了成为别人的工作 富有成效的。 C#的目的是 一种有用的编程语言 使我们的客户能够提高生产力 在我们的平台上。显然 OOP 是两者 有用且受欢迎,我们已经 因此试图使其易于 在 C# 中以 OOP 样式编写程序。但是 C# 的目的不是“成为 OOP 语言”。我们评估基于 关于它们是否对我们有用 客户,而不是基于他们是否 严格符合一些抽象的 什么使一个学术理想 语言面向对象。好吧 愉快地接受oo的想法, 功能性、程序性、命令性、 声明性的,无论如何,只要我们 可以制造出一致的、有用的产品 这使我们的客户受益。
【讨论】:
谢谢。很好的解释。所以你认为效用方法是一种很好的做法,对吧?但是我不明白为什么人们会使用静态而不是“私有”或“实用程序”。基本上,我经常使用实用方法。 好吧,任何时候你都可以编写一个逻辑上与类型有关的方法,而不是类型的实例。在某些地区,这很常见;在其他情况下,这种情况很少见。 第一个实例,我不明白静态方法不能被替换。经过一些研究,我意识到在测试中很难(如果不是不可能的话)用模拟替换它们。【参考方案2】:我想说当静态方法是函数时肯定没问题,即它们不做任何IO,没有任何内部状态,只使用它们的参数来计算它们的返回值价值。
我也会将此扩展到更改其参数状态的方法,但如果这样做过度,静态方法应该适当地成为它主要操作的参数类的实例方法。
【讨论】:
【参考方案3】:想一想。在 OO 编码中,每个函数调用实际上都是这样的:
method(object this, object arg1, object arg2)
这是您正在调用的对象。它实际上只是语法糖。此外,它允许您清楚地定义变量的范围,因为您有对象变量等。
静态方法根本没有“this”参数。即你传入变量并可能得到一个结果。 1.) 是人们避免使用它们的主要原因,你不能创建静态方法的接口(还)所以你不能模拟出静态方法来测试它。
其次,OO 是过程函数等。静态方法在某些情况下很有意义,但它们总是可以变成对象上的方法。
请注意,如果没有 hack,您将无法删除它:
static void Main(string[] args)
启动您的应用程序的代码必须可以在不引用对象的情况下调用。因此它们为您提供了灵活性,您是否选择在您的场景中使用它们将取决于您的需求。
【讨论】:
“你不能创建一个静态方法的接口(还)” 10 年后,还在等待......【参考方案4】:在单例模式提供太多灵活性的大多数情况下,静态方法都很好。
例如,使用一个简单的实用程序,例如将原语提升为幂 - 显然您永远不需要任何多态性。原始值是静态类型的,数学运算定义明确并且不会改变。你不会遇到有两个differentimplementations 的情况,如果不重写所有客户端代码就无法在它们之间切换。
(讽刺关闭)
如果只加载一个接口的一个实现,现代 JVM 非常擅长内联小型调用。除非您已经分析了您的代码并且知道将您的实用程序分派到一个接口是一种开销,否则您没有理由不创建您的 utility methods into an interface,如果需要,您可以更改它。
【讨论】:
【参考方案5】:静态方法的另一个好场景是Factory pattern 的实现,您可以在其中允许以特定方式构造类的实例。
考虑Calendar
类,它具有一组静态getInstance
方法,每个返回的实例都使用所需的TimeZone
和/或Locale
或默认值进行初始化。
【讨论】:
我不使用依赖注入也不(通常)模拟对象进行测试,但实现工厂的静态方法会使模拟变得不可能,不是吗?【参考方案6】:我认为静态方法的一个明确情况是当你不能使它们动态时,因为你不能修改类。
这是典型的 JDK 对象,以及来自外部库的所有对象,以及原始类型。
【讨论】:
【参考方案7】:我经常使用静态工厂方法来代替或与公共构造函数结合使用。
当我需要一个构造函数来做一些你不希望构造函数做的事情时,我会这样做。 IE。从文件或数据库加载设置。
这种方法还提供了命名“构造函数”的可能性,基于它们所做的事情。当参数本身不足以弄清楚构造函数中发生了什么时,这尤其有用。
Sun 在
中使用了这种方法Class.forName("java.lang.Integer");
和
Boolean.valueOf("true");
【讨论】:
【参考方案8】:首先,你不能放弃静态方法,人们仍在使用它是有原因的。
一些设计模式基于静态方法,例如单例:
Config.GetInstance();
Helper 函数,假设您有一个字节流,并且您想要一个函数将其转换为十六进制数字字符串。
静态方法有很多用途,这并不意味着有些人滥用它太多(当人们滥用代码时,代码审查是最好的选择)。
【讨论】:
【参考方案9】:Util 类可以是静态的。与上面其他人的示例一样,使用转义字符串。问题在于当这些 utils 类执行我们想要模拟的功能时。例如,apache commons 中的 FileUtils 类——通常情况下,我想模拟文件交互而不必使用真实文件。如果这是一个实例类,那就很容易了。
【讨论】:
【参考方案10】:重构静态方法要容易得多。它不鼓励对使耦合紧密的字段成员进行不必要的引用。调用代码也更容易理解,因为它显式传递了与之交互的任何对象。
【讨论】:
【参考方案11】:通常,当单个实例可以正常工作时,我会避免使用静态方法。该单个实例可以实现一个接口并且可以轻松地模拟。我不是说从不,但我很少使用静力学。我告诉我的团队如果他们想使用静态,应该由团队清除。几乎从来都不是我的答案。
【讨论】:
以上是关于在啥情况下静态方法是一个好习惯?的主要内容,如果未能解决你的问题,请参考以下文章