何时编写静态方法与实例方法的编码是否有经验法则?

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

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

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

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

我们想到的值得注意的例外是Factory Method和Singleton(使用节制)模式。 当你想要编写一个“助手”类时要谨慎,因为从那里开始,它是程序编程的一个滑坡。

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

在像Java或C ++这样的语言中,我承认静态方法使代码不那么优雅,所以还有一个权衡。 在C#中,扩展方法可以为您提供两全其美的优势。

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

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

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

即使该方法不改变状态(实用程序function),我建议您使用实例方法。 主要是因为这种方式你可以有一个子类来执行不同的操作。

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

🙂

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

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

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

如果不是,那取决于你,但是如果你发现自己有很多静态方法和/或静态非最终变量,你可能想要将所有静态内容提取到一个新的类实例中。 (一堆静态方法和成员是一个单独的,但是真的很烦人,有一个真正的单例对象会更好 – 一个常规对象,恰好是最好的!)。

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

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

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

恕我直言,如果你可以使它成为一个静态方法(无需改变它的结构),那么使它成为一个静态方法。 它更快,更简单。

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

一般来说,一旦你想象有一天使用它就不应该添加function(这种方式就是疯狂),你应该只添加你确实需要的function。

更长的解释……

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

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

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

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

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

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