Mik*_*ike 35 java oop static-methods scala language-concepts
我在阅读Programming Scala.在第4章的开头,作者评论说Java支持静态方法,这些方法是"不那么纯粹的OO概念".为什么会这样?
Jör*_*tag 61
面向对象大约有三件事:
在这三个中,最重要的一个是消息传递.
静态方法至少违反了消息传递和后期绑定.
消息传递的思想意味着在OO中,计算由自包含对象的网络执行,这些对象向对方发送消息.发送消息是通信/计算的唯一方式.
静态方法不这样做.它们与任何对象无关.他们真的没有方法可言,按照通常的定义.他们真的只是程序.Java静态方法Foo.bar
和BASIC子例程之间几乎没有区别FOO_BAR
.
至于后期绑定:更现代的名称是动态调度.静态方法也违反了这一点,事实上,它甚至以它们的名字命名:静态方法.
静态方法打破了面向对象的一些非常好的属性.例如,面向对象的系统在对象充当功能时自动具有功能安全性.静态方法(或任何静态方法,无论是静态方法还是静态方法)都会破坏该属性.
您还可以在自己的进程中并行执行每个对象,因为它们只通过消息传递进行通信,从而提供一些简单的并发性.(就像Actors一样,基本上,这不应该太令人惊讶,因为Carl Hewitt创建了基于Smalltalk-71的Actor模型,而Alan Kay创建的Smalltalk-71部分基于PLANNER,而后者又由Carl Hewitt创建.演员和对象之间的关系远非巧合,事实上,它们本质上是同一个.)同样,静态(静态方法,尤其是静态方法)打破了这个不错的属性.
Gab*_*abe 32
不要将"不那么纯粹的OO概念"与"不良实践"混为一谈.作为"纯粹的OO"并不是你应该尝试实现的灵丹妙药.仅仅因为静态方法不将实例变量作为参数并不意味着它们没有用处.有些事情本身并不适用于物体,为了"纯洁",它们不应该被迫进入那种模具.
有些人认为事情应该是"纯粹的",因此任何"不纯"都是不好的做法.实际上,糟糕的做法只是做一些令人困惑,难以维护,难以使用的事情等.创建带有实例的静态方法是不好的做法,因为任何采用实例的方法都应该是实例方法.另一方面,实用程序和工厂函数之类的东西通常不会占用实例,因此它们应该是静态的.
如果你想知道他们为什么不是"纯粹的OO",那是因为它们不是实例方法."纯粹的"OO语言将所有东西都作为对象,所有函数都是实例方法.当然,这并不是一直非常有用.例如,考虑该Math.atan2
方法.它需要两个数字,不需要任何状态.您甚至可以将它作为一种方法的对象是什么?在"纯粹的"OO语言中,Math
它本身可能是一个对象(可能是单例),并且atan2
是一个实例方法,但由于该函数实际上并不使用Math
对象中的任何状态,因此它也不是"纯粹的OO" "概念.
Edd*_*die 25
迄今为止尚未提及的静态方法不是非常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;
}
}
Run Code Online (Sandbox Code Playgroud)
当你运行它时,你将无法得到你所期望的. Test.returnValue()
给出你所期望的. Test2.returnValue()
隐藏超类中相同名称的方法(它不会覆盖它),它给出了你所期望的.
人们可能天真地期望"非静态地"调用静态方法来使用多态.它没有.声明变量的类是用于查找方法的类.这是一种糟糕的形式,因为有人可能希望代码执行与实际操作不同的操作.
这并不意味着,"不要使用静态方法!" 它确实意味着您应该为那些您真正希望Class对象拥有该方法的实例保留静态方法的使用,而不仅仅是作为制作单例的懒惰方式.
由于以下原因,静态方法不被视为良好的面向对象实践:
1) 防止重复使用:
静态方法不能被覆盖。它不能在界面中使用。
2)对象生命周期很长:
静态方法会在内存中保留一段日志时间,并且其垃圾收集需要很长时间。开发人员无法控制静态变量的销毁或创建。静态变量的过度使用会导致内存溢出。
3)另外,还有一些要点:
它不尊重封装,因为对象不会完全控制其状态。它不遵循控制反转、松耦合、依赖注入等概念。
静态方法导致紧耦合,这违反了良好的面向对象设计.无法通过依赖倒置避免调用代码和静态方法中的代码的紧密耦合,因为静态方法固有地不支持面向对象的设计技术,例如继承性和多态性.
除了静态方法很难测试因为这些紧密耦合的依赖关系,这通常会导致代码依赖的第三方基础结构 - 比如数据库,并且很难在不实际进入和更改的情况下更改行为码.