最近跟某位朋友讨论了一些工作上的事情,他目前就职于某世界500强IT公司,在他们现在做的一个项目中,整个系统构架是完全面向对象的,而且他对这种框架极其推崇,不过他们经常加班到深夜,有时周末也要加班,笔者当时从直觉上觉得这里有问题,回去之后仔细反思,搜索了一些资料,算是找到了他们为什么这么累的原因吧。

面向对象(Object Oriented,OO)是当前计算机界关心的重点,它是90年代软件开发方法的主流,不过随着时代的发展,很多人对OO编程方法的看法也出现了一些变化;
最近在网上面看到有个名人针对面向对象的文章,我们可以先看一看:
“面向对象编程是一个极其糟糕的主意,只有硅谷里的人能干出这种事情。” — Edsger Dijkstra(图灵奖获得者)
“面向对象设计是用罗马数字做计算。” — Rob Pike(Go语言之父)
““面向对象”这个词包含很多意思。有一半是显而易见的,而另一半是错误的。“ — Paul Graham(美国互联网界如日中天的教父级人物)
“实现上的继承就跟过度使用goto语句一样,使程序拧巴和脆弱。结果就是,面向对象系统通常遭受复杂和缺乏复用的痛苦。” — John Ousterhout( Tcl and Tk 的创始人) Scripting, IEEE Computer, March 1998
“90%的这些胡说八道都称现在它很流行,非要往我的代码里搓揉进面向对象的石粒。” — kfx
“有时,优雅的实现只需要一个函数。不是一个方法。不是一个类,不是一个框架。只是一个方法。” — John Carmack(id Software的创始人、第一人称射击游戏之父)
“面向对象编程语言的问题在于,它总是附带着所有它需要的隐含环境。你想要一个香蕉,但得到的却是一个大猩猩拿着香蕉,而其还有整个丛林。” — Joe Armstrong(Erlang语言发明人)
“我一度曾经迷恋上了面向对象编程。现在我发现自己更倾向于认为面向对象是一个阴谋,企图毁掉我们的编程乐趣。” — Eric Allman(sendmail的创造者)
——摘自: 面向对象编程从骨子里就有问题
下面我们来分析一下他们为什么讨厌面向对象,过度追求OO到底有什么问题:

面向对象的生产效率

这是OO编程比较推崇的一点,不过我们可以先看看这篇文章: 如此理解面向对象编程
在文章中,某“***”,将下面一段代码,“面向对象”成了7个文件,代码量由原来的几行变成了几十行。
public class PrintOS
{
public static void main(final String[] args)
{
String osName = System.getProperty("os.name") ;
if (osName.equals("SunOS") || osName.equals("Linux"))
{
System.out.println("This is a UNIX box and therefore good.") ;
}
else if (osName.equals("Windows NT") || osName.equals("Windows 95"))
{
System.out.println("This is a Windows box and therefore bad.") ;
}
else
{
System.out.println("This is not a box.") ;
}
}
}
文中的这位“***”将学院派的做法发挥到了极致。虽然这只是一个OO的教学文档,但确实很像OO的一篇高级黑,但我们仍能看出一味地追求OO会增加多么大的代码量。你现在明白你为什么需要IDE来辅助了吧? 在茫茫多的文件中寻找一个变量是多么的不容易呀。

面向对象的性能
这篇文章详细地讨论了OO的性能: Pitfalls Of Object Oriented Programming.
文中指出,从1980年至今,CPU的性能提高了近10W倍,但内存的访问性能只提高了不足10倍,原因就是内存的访问相对速度大为降低,OO的滥用使程序要经过很多间接过程才能访问到目标内存地址,
因而过度使用面向对象,会严重影响性能,作者推荐优化数据和代码结构为先,并尽量使用KISS(keep it simple, stupid)原则来设计软件。

面向对象的可维护性
面向对象从一开始就要求我们完全了解各个子类的不同,并将他们的“共性”提取到父类里,从而实现代码复用,在这个过程中自然形成了一种最强的耦合关系。这种设计方法在需求非常确定的情况下是有效的,但在实际生活中我们发现需求总是在开发过程中不断提出的,而且也总在变化,甚至跟之前完全相反,当你看到你精心设计的框架成为你需求变更的障碍时,你做何感想?
在一个完全OO的系统中,我们会不自觉地使用设计模式驱动型编程,正如这种编程的名字所说的,这种编程风格使用大量的设计模式,在你的程序中,四处都是设计模式,你的代码到处都是 Facade,Observer ,Strategy,Adapter,等等等等。于是,你的程序要处理的业务逻辑被这些设计模式打乱得无法阅读,最后,也不知道是业务需求重来,还是设计模式重要,总之,实际业务需求的程序逻辑被各种设计模式混乱得不堪入目。

该如何面向对象

本文并不是完全否定面向对象的编程方法,经过上面的分析,我们已经可以发现,OO比较适合需求确定,耦合度高的子模块中使用; 但在一个需求在不断变化,业务逻辑在不断增加的复杂系统中,面向模块也许是更好的选择。