[转]谈谈面向对象编程的几个问题
我不是个喜欢”深究“的权威型工程师,所以一些观点并不敢保证精准和正确。我喜欢就自己的经验,谈一下个人的理解,如果说错什么,敬请批评指正。
1)关于面向“类”和面向“对象”的问题
面向对象编程是种编程范式,在提出这种范式之初,关心的东西只有“对象”和“对象间的消息传递机制”。而随着面向对象范式在语言层面的不断探索,于是出现了“类”的概念,有了面向对象三大特点“封装”、“继承”和“多态”。现在有不少人在追本朔源,说“面向对象”现在变成了”面向类“,已经不再是它的初衷了,面向对象走向了错误了方向,应该反思。
反思是应该的,追本朔源可以帮助我们站在一个更高的角度来看问题。但结论我并不认同,私以为”类“的概念的提出,是对”面向对象“在实践方面的一个很好的补充和完善,它属于”面向对象“理念的”实践“,而且是一个非常好非常精彩的实践。我承认在当今的实践中,面向”对象“实在太容易变成面向”类“了,类的作用非常重要,可是我并不觉得提高类的重要性对编程带来了多大的麻烦。类的作用变得如此之大,我觉得并非”走火入魔,误入歧途“,而是”自然发展,自然选择“。没必要为”类“的重要性太高而纠结。
2)设计模式的问题
设计模式在过去的一段时间里,温度有点过高了,甚至在很多初学者看来,似乎以”设计模式“为编程技巧的终点了,有点把它当《九阴真经》了。其实设计模式是个什么东西呢?设计模式是在”面向对象“这种编程范式的基础上,提练的一套编程技巧,解决的是”面向对象编程时,如何去抽象类,设计类“这个问题。
面向对象编程,应该分为”OOA“、”OOD“和”OOP“三个步骤。OOP是和具体语言相关的,不同语言的语法是有差异的,比如c#、as3、java、ruby、python等都是面向对象语言,但不同语言的语法差异还是比较大的。OOP是大多数工程师们特别关心的问题,因为这是他们跨入编程圈会遇到的第一个问题。很多人会误以为它是面向对象编程的全部,特别是只看过语言基础教程的工程师。其实不是,而且OOP甚至不是面向对象编程的重点,OOA和OOD才是。
OOA和OOD是面向对象分析和面向对象设计。将客观世界的看得见的实物或者逻辑层面的看不见的物件,转换成程序中的一个个对象,用属性和方法来描述对象,这种转换的过程我们管他叫”抽象“,也可以叫做OOA。这里有个问题就是:同样的一个需求,你可以做完全不同的抽象,设计出几套完全不同的对象。有些方案好,有些方案可能不好——虽然他们都能解决问题,但可能在可维护性上(健壮性、可读性、可扩展性等等)有非常大的差异。
于是有了OOD,有了设计模式。设计模式的作用是告诉你”面对类似xxxx这样的需求,你可以抽象成这么几个类:A和B,其中A有哪些方法和属性,B有哪些方法和属性,他们如何配合工作。设计成A和B这样的类,可以为你带来什么什么样的好处“。
虽然设计模式之父GOF四人组介绍了23种设计模式,但事实上,常用的设计模式只有那么几种。而且每本设计模式的书,都会告诉你,不要为了设计模式而设计模式。这东西只是用来帮助你解决一些设计问题的,而且以我的经验来说,设计模式既不难理解,也并不是那么必要,离《九阴真经》的定位差远了。学学有必要,但完全不用对这玩意儿过于纠结,甚至不用过于上心。如果经验慢慢积累够了,在OOA的时候,不必借助设计模式,你也可以很好地OOD了。
3)面向对象最重要,却又容易被忽视的问题——编程技巧
不知道编程技巧算不算是OOP的一部分,算或不算都有道理,因为它虽是编程方面的技巧,却和程序语言的关系不大,可以跨语言通用。面向对象在实战中,最大的难点应该在如何让对象”高内聚低耦合“。高内聚说白了,就是在抽象对象时,能让你抽象出来的对象”属性和方法能高度重用“,这个重用或许是自己调自己,或许是别的对象调自己,被调用的机会越多,内聚得越厉害。如果一个对象的某些属性和方法被调用的次数很少,可以考虑将其拆解一下,拆成两个或更多的类,借此提高这些对象的内聚性。
而低耦合就好理解多了,一个对象对其他对象的依赖性越低,知道的越少,耦合度越低。如何降低耦合度,是需要编程技巧的,虽然OOA和OOD也能帮助解决这个问题,但编程技巧上也需要一些方法,比如尽量私有、通过命令模式拆分开m和c从而解除对象间的直接调用、增加常量减少变量等等等等。
在编程技巧方面的学习,重要性和实用性都比设计模式更高。而这方面其实又不会像设计模式这样有书可以看,也不是通过自己顿悟能够悟出来的,最有效的方法是去看别人的代码,看高质量开源框架的源码,多学不同领域的知识,融会贯通。
4)面向对象编程和函数式编程
大概在三四年前,面向对象编程几乎一致被看好和膜拜。然后在过去一两年,似乎对面向对象编程的质疑变多了,有些工程师很推崇函数式编程了。对于函数式编程,我没有研究过,所以不好发表意见。这里只说一点私人看法,如果说错了,请见谅。
函数式编程的历史很悠久了,和面向对象编程范式一样,也是一种基本的编程范式,围绕这种范式也产生了一系列的编程技巧:比如传参时参数有默认值、参数数量可变、装饰器等等,它有和面向对象不同的关注点和相应的优势。但,私以为面向对象还是大势所趋,从主流语言的市场份额、市面上的书籍数量、思维习惯易上手性和主流的编程范式等多个方面来说,面向对象应该都是优势明显的。
很多人在说面向对象有很多问题,不好。而函数式编程可以解决这些问题。私以为,面向对象本身其实应该是非常好的。面临的一些问题,会不会是因为很多工程师缺少编程技巧而造成的?因为面向对象是主流,所以使用的人多,暴露的问题也就越明显,就像windows的病毒远比macos多一样,原因并非macos安全性高,而是windows被黑的太多了。
所以函数式编程,如果有时间的话,可以学习一下,丰富自己的编程技巧,但正常情况下,我建议还是随大流,专心把面向对象编程玩好吧。