49

我正在阅读Programming Scala。在第 4 章的开头,作者评论说 Java 支持静态方法,这是“不那么纯粹的 OO 概念”。为什么会这样?

4

7 回答 7

72

面向对象是关于三件事:

  • 消息传递,
  • 状态过程的本地保留、保护和隐藏,以及
  • 所有事物的极端后期绑定。

在这三个中,最重要的一个是消息传递

静态方法至少违反了消息传递和后期绑定。

消息传递的概念意味着在 OO 中,计算是由相互发送消息的自包含对象网络执行的。发送消息是通信/计算的唯一方式。

静态方法不这样做。它们不与任何对象关联。根据通常的定义,它们根本不是方法。它们实际上只是程序。Foo.barJava 静态方法和 BASIC 子例程之间几乎没有区别FOO_BAR

至于后期绑定:一个更现代的名称是动态调度。静态方法也违反了这一点,事实上,它甚至以它们的名字命名:静态方法。

静态方法破坏了面向对象的一些非常好的属性。例如,面向对象的系统是自动能力安全的,对象作为能力。静态方法(或任何静态方法,无论是静态还是静态方法)都会破坏该属性。

您还可以在其自己的进程中并行执行每个对象,因为它们仅通过消息传递进行通信,从而提供一些微不足道的并发性。(基本上就像Actors一样,这不应该太令人惊讶,因为 Carl Hewitt 基于 Smalltalk-71 创建了 Actor 模型,而 Alan Kay 创建了 Smalltalk-71 部分基于由 Carl Hewitt 创建的 PLANNER。演员和对象之间的关系绝非巧合,事实上,它们本质上是相同的。)再次,静态(静态方法,尤其是静态)打破了这个好的属性。

于 2010-10-23T03:45:58.517 回答
40

不要将“不那么纯粹的 OO 概念”与“不好的做法”混为一谈。成为“纯 OO”并不是您应该尝试实现的灵丹妙药。仅仅因为静态方法不将实例变量作为参数并不意味着它们没有用。有些东西就是不适合对象,不应该仅仅为了“纯洁”而被迫进入那种模式。

有些人认为事物应该是“纯净的”,因此任何“不纯净”的东西都是不好的做法。实际上,不好的做法只是做一些令人困惑、难以维护、难以使用等的事情。创建采用实例的静态方法是不好的做法,因为任何采用实例的方法都应该是实例方法。另一方面,实用程序和工厂函数之类的东西通常不采用实例,因此它们应该是静态的。

如果您想知道为什么它们不是“纯 OO”,那是因为它们不是实例方法。“纯”面向对象语言将所有内容都作为对象,所有函数都是实例方法。当然,这并不是一直都非常有用。例如,考虑Math.atan2方法。它需要两个数字,不需要任何状态。你甚至可以把它变成什么对象的方法?在“纯”面向对象语言中,Math它本身可能是一个对象(可能是单例),并且atan2可能是一个实例方法,但由于该函数实际上并未使用Math对象中的任何状态,因此它也不是“纯面向对象” “ 概念。

于 2010-10-23T02:52:32.340 回答
35

静态方法不是很 OO 的一个原因是到目前为止还没有提到接口和抽象类只定义非静态方法。因此,静态方法不太适合继承。

另请注意,静态方法无权访问“ super”,这意味着在任何实际意义上都不能覆盖静态方法。实际上,它们根本无法被覆盖,只能隐藏。试试这个:

public class Test {
    public static int returnValue() {
        return 0;
    }

    public static void main(String[] arg) {
        System.out.println(Test.returnValue());
        System.out.println(Test2.returnValue());
        Test x = new Test2();
        System.out.println(x.returnValue());
    }
}


public class Test2 extends Test {
    public static int returnValue() {
        return 1;
    }
}

当你运行它时,你不会得到你所期望的。 Test.returnValue()给出你所期望的。 Test2.returnValue() 在超类中隐藏同名的方法(它不会覆盖它),并且它给出了你所期望的。

人们可能天真地期望“非静态地”调用静态方法来使用多态性。它没有。无论变量声明为哪个类,都是用于查找该方法的类。这是一种不好的形式,因为有人可能希望代码执行与实际执行不同的操作。

这并不意味着“不要使用静态方法!” 这确实意味着您应该为那些您确实希望 Class 对象拥有该方法的实例保留使用静态方法,而不仅仅是作为制作单例的一种懒惰方式。

于 2010-10-23T02:54:45.647 回答
11

静态方法会导致紧密耦合,这违反了良好的面向对象设计。调用代码和静态方法中代码的紧密耦合无法通过依赖倒置来避免,因为静态方法本身不支持面向对象的设计技术,例如继承和多态。

此外,由于这些紧密耦合的依赖关系,静态方法很难测试,这通常会导致代码依赖的第三方基础设施——比如数据库,并且如果不实际进入并更改代码。

于 2017-09-28T21:33:52.167 回答
9

由于以下原因,静态方法不被视为良好的 OO 实践:

1) 防止重复使用:

静态方法不能被覆盖。它不能用于界面。

2)对象生命周期很长:

静态方法会在内存中保留一段时间,并且其垃圾收集需要很长时间。开发人员无法控制静态变量的销毁或创建。过度使用静态变量会导致内存溢出。

3)另外,还有一些其他的点:

它不尊重封装,因为对象不会完全控制其状态。它不遵循控制反转、松散耦合、依赖注入等概念。

于 2017-10-21T17:27:13.967 回答
2

静态方法不是那么纯粹的 OO 概念,因为它们可以在没有对象实际关联的情况下被调用。您使用类本身。你像这样调用它们Classname.method(...);

于 2010-10-23T02:48:06.173 回答
0

OO的概念是谈论控制/访问来自对象的数据,但是静态方法不需要使用对象调用,它们属于类而不是对象。

- 干杯

于 2010-10-23T02:51:09.397 回答