7

我正在学习 Java(和 OOP),尽管它可能与我现在所处的位置无关,但我想知道 SO 是否可以分享一些常见的陷阱或良好的设计实践。

4

13 回答 13

14

要记住的一件重要事情是静态方法不能被子类覆盖。代码中对静态方法的引用本质上将其与该实现联系在一起。使用实例方法时,行为可以根据实例的类型而变化。您可以利用多态性。静态方法更适合于行为一成不变的功利型操作。例如 base 64 编码或计算校验和。

于 2009-01-24T00:13:39.417 回答
10

我认为任何答案都没有触及 OO 的核心,即何时选择其中一个。当然,当您需要处理实例成员时使用实例方法,但您可以将所有成员设为公开,然后编写一个静态方法,将类的实例作为参数。你好ç。

您需要考虑您正在设计的对象响应的消息。这些将永远是您的实例方法。如果你以这种方式考虑你的对象,你几乎永远不会有静态方法。静态成员在某些情况下是可以的。

想到的值得注意的例外是工厂方法和单例(谨慎使用)模式。当你想写一个“助手”类时要小心,因为从那里开始,它是进入过程编程的一个滑坡。

于 2009-01-24T00:46:42.407 回答
3

如果一个方法的实现可以完全用你的类的公共接口(没有向下转换)来表达,那么它可能是静态“实用程序”方法的一个很好的候选者。这允许您维护一个最小的接口,同时仍然提供代码客户端可能经常使用的便利方法。正如Scott Meyers 解释的那样,这种方法通过最大限度地减少因更改类的内部实现而影响的代码量来鼓励封装。这是 Herb Sutter 的另一篇有趣的文章,他将 std::basic_string 分解,决定哪些方法应该是成员,哪些不应该。

在像 Java 或 C++ 这样的语言中,我承认静态方法会使代码不那么优雅,因此仍然需要权衡。在 C# 中,扩展方法可以为您提供两全其美的方法。

如果由于某种原因该操作需要被子类覆盖,那么它当然必须是实例方法,在这种情况下,您需要考虑设计继承类的所有因素。

于 2009-01-24T00:43:41.120 回答
1

我的经验法则是:如果该方法执行与类的特定实例相关的任何事情,无论它是否需要使用类实例变量。如果您可以考虑可能需要使用某个方法而不必引用类的实例的情况,那么该方法绝对应该是静态的(类)。如果此方法在某些情况下也碰巧需要使用实例变量,那么最好创建一个单独的实例方法来调用静态方法并传递实例变量。在性能方面,我相信差异可以忽略不计(至少在 .NET 中,尽管我认为 Java 会非常相似)。

于 2009-01-23T23:54:48.253 回答
1

如果您保留对象的状态(值)并且该方法用于访问或修改状态,那么您应该使用实例方法。

即使该方法不会改变状态(实用函数),我也建议您使用实例方法。主要是因为这样你可以有一个执行不同操作的子类。

其余的你可以使用静态方法。

:)

于 2009-01-24T00:21:56.373 回答
0

该线程看起来很相关:方法可以设为静态,但应该这样做吗?C# 和 Java 之间的差异不会影响其相关性(我认为)。

于 2009-01-23T23:53:27.400 回答
0

您的默认选择应该是实例方法。

于 2009-01-24T00:32:33.293 回答
0

如果它使用实例变量,则它必须是实例方法。

如果没有,这取决于您,但如果您发现自己有很多静态方法和/或静态非最终变量,您可能希望将所有静态内容提取到一个新的类实例中。(一堆静态方法和成员是一个单例,但真的很烦人,拥有一个真正的单例对象会更好——一个常规对象恰好是其中之一,最好的!)。

于 2009-01-24T00:34:45.223 回答
0

基本上,经验法则是它是否使用特定于对象、实例的任何数据。所以 Math.max 是静态的,但 BigInteger.bitCount() 是实例。显然,随着您的域模型变得更加复杂,并且存在边界情况,但总体思路很简单。

于 2009-01-24T00:49:48.627 回答
0

我会默认使用实例方法。优点是可以在子类中覆盖行为,或者如果您针对接口进行编码,则可以使用协作者的替代实现。这对于测试代码的灵活性非常有用。

静态引用被嵌入到您的实现中并且无法更改。我发现 static 对于短实用程序方法很有用。如果您的静态方法的内容非常大,您可能需要考虑将职责分解为一个或多个单独的对象,并让这些对象作为对象实例与客户端代码协作。

于 2009-01-24T01:00:54.097 回答
0

恕我直言,如果您可以将其设为静态方法(无需更改其结构),则将其设为静态方法。它更快,更简单。

如果您知道要覆盖该方法,我建议您在实际执行此操作的地方编写一个单元测试,因此不再适合将其设为静态。如果这听起来太辛苦了,那就不要让它成为一个实例方法。

通常,您不应该在您想象有一天使用时立即添加功能(那是疯狂的所在),您应该只添加您知道您实际需要的功能。

对于更长的解释......

http://en.wikipedia.org/wiki/You_Ain%27t_Gonna_Need_It

http://c2.com/xp/YouArentGonnaNeedIt.html

于 2009-01-24T07:07:33.420 回答
0

静态方法的问题在于,当您与实现耦合时,您正在破坏核心的面向对象原则之一。您希望支持开闭原则并让您的类实现一个描述依赖关系的接口(在行为抽象意义上),然后让您的类依赖于该接口。在那一点之后更容易扩展。..

于 2009-01-24T12:14:06.437 回答
0

我的静态方法总是以下之一:

  1. 评估仅对该类有用的公式的私有“助手”方法。
  2. 工厂方法(Foo.getInstance()等)
  3. 在一个最终的“实用程序”类中,有一个私有构造函数并且除了公共静态方法之外什么都不包含(例如com.google.common.collect.Maps

我不会仅仅因为它不引用任何实例变量而将方法设为静态。

于 2009-09-11T23:41:52.337 回答