编程新手如何理解“面向对象”
先说一点,其实我是不建议新手去“深入”理解面向对象的。所谓“深入”,大概就以“设计模式”为界吧。通常情况下,两年工作经验以下的新人,去研究“设计模式”要么是半途而废(这算是好的),要么就是把自己搞废了(走火入魔)。
这些年,谈“设计模式”的人确实是越来越少了,而且前两天我看到一个问题:面向对象(OOP)是编程语言发展中的弯路吗?为什么?
这个有点狠,呵呵。“弯路”倒谈不上,只能说现在“面向对象”已经被拉下神坛,回归常态:不再是“万物皆对象”的狂热,而应该是在适合面向对象的地方面向对象。
不知道大家是否同意:设计模式本质上是对传统面向对象“弊端”的一种修补?这个说得深了一点,新手随便看看就行。
说正事,编程新手应该如何理解“面向对象”?
首先,面向对象仍然是目前最主流、最有效地处理复杂业务逻辑的手段。大家不要矫枉过正,听有些家伙叫嚣“面向对象已死”啥的。那么多以前不支持面向对象的语言(比如php/JavaScript)都在尽力的往对象上面靠,就是一个明证。当然,学习面向对象,最好还是通过纯粹的、原生支持面向对象的语言,比如C#和Java,强烈不建议通过JavaScript学习面向对象——太残太拧太伤心……
其次,大家要明白“面向对象”要解决的问题,或者它使用的场景。面向对象并不适用于你在学习各种语言语法时写的那些Demo程序(比如“冒泡排序”“图书/课程管理系统”啥的),甚至于大多数的小型开发项目(比如普通的企业网站、个人博客)都不适合。面向对象适合的是那些业务逻辑复杂(其实用“繁杂”更恰当一些)的大型项目。所谓繁杂,繁指多,杂指乱,项目“杂乱”,可以表现为:功能多改动多,所以代码量大、开发人员多、开发/维护跨度时间长……
这个我接下来还要继续讲,但大家先一定要有这个意识。不然你老是用“面向对象”套你那几个小项目,怎么抽象怎么封装,肯定会越整越晕。小项目里,“面向对象”没用,体现不出来“面向对象”的那些好处——这也还是为什么我一开始就讲“不建议新手去‘深入’理解面向对象”的原因,这个阶段,你接触的项目规模有限,对代码复杂性的理解有限,很难体会“面向对象”的作用。
最后,我给大家勾勒出理解面向对象的几个层次,由浅入深,大家可以依次理解。
1、学会面向对象的语法。类的声明和继承、接口和抽象类、方法和属性、访问修饰符……这个没啥说的,非常简单,都应该掌握。
2、想明白为什么会出现“类”。我推荐如何通俗易懂地举例说明“面向对象”和“面向过程”有什么区别?里匿名用户的高赞回答,简单的说,函数太多,要分“类”管理。这就够了,然后在实际开发工作中,试着把类分好,清晰有条理就可以了。
3、明白“对象”是方法(函数)和数据的组合。因为如果你只停留在第2点的理解上,所有的类其实就是静态类,所有的方法都是静态方法。但类的一大特点,就是它自身是包含数据的,而且不同的数据可以造就不同的实例(对象)。你看,直到这个时候,我们才能说面向对象,而不是面向类。
4、开始“继承”。注意,从这里开始,就可能有陷阱了。继承实际上带来了两个结果:重用和多态。重用非常好理解,子类能够使用父类所有非私有的属性和方法嘛,所以很多同学一使用继承,就奔着“重用”去了。比如狗有四条腿,猫也有四条腿,那就抽象出一个有四条腿的父类:动物……但这样做的问题是:桌子也有四条腿,咋整?由于事物之间复杂的共性/特性关系,很容易就整出多重继承出来,比如你开始是这样构想的:
一切都非常美好,但是,接下来“鸭子”怎么办?你觉得它应该是禽类,但是请注意,它也是会游泳的(代码里需要这个功能)。同理,还有公鸡,它也可以产肉,又该怎么办?还有漂亮的画眉,就是用来观赏的,咋整?动物越来越多,这个体系就崩溃了……
所以这里其实是可以批评“面向对象”的第一个点,或者层面。但是,永远不要因为一门技术有这样那样的问题,就轻易的放弃。随着你学习的深入,你可以有更深层次的理解。
5、用组合实现重用,用继承实现多态。这实际上是对第4条的一次“修补”(注意:不是“颠覆”)。我个人认为,这其实是“设计模式”的基础或者核心。对于初学者而言,理解到这里就差不多了;要讲起来,也非常非常的难了。这几乎上升到一种“艺术”的范畴了,好吧,飞哥承认,我自己对此的理解——理解可能是理解了,但应用起来还是捉襟见肘,不是很溜。就像你知道了很多公式,一样解不出一道数学题一样。
问题在哪里?我称之为“复杂度守恒”。有的同学或者听说过“‘面向对象’的设计能够降低复杂度”……但实际上,并没有。业务逻辑的复杂度永远是不可能降低的,除非你改需求;需求就是那样了,所以复杂度就在哪里了,你怎么降低?无论是面向对象,还是设计模式,和不面向对象编程(比如结构化编程)相比,其本质是把复杂度转移到类的关系复杂度上。
我感觉我好像又说得深了一点?就再说一点就停,可能有同学知道工厂模式,能够干掉丑陋的switch...case...,但是,switch...case...这种逻辑,真的消失了吗?没有啊!同学,它不过是通过类的继承和多态实现了呀。你觉得if...else...嵌套非常复杂,但数不清的类的关系一样复杂啊!
我说这些,如果你是新人,可能根本体会不到。可能if...else...嵌套的复杂都还体会不到,就不用说其他了。所以,就此打住吧。我觉得新人能够掌握第3个层次,理解到第4个层次,摸到第5个层次的边,就非常非常不错了。
可能有些同学看了4和5,会觉得:那“面向对象”就确实没有价值啊!就算是做到了第5个层次,也不过是“转移”了复杂度而已。既然if...else...的嵌套和子类父类一样复杂,我干嘛要选择子类父类这种复杂呢?
Good question!
我能给你最简单的回答,两个原因:
1、“人脑”的局限。面对复杂事物,人脑的自然处理方式就是“抽象”和“屏蔽细节”。
假设你现在是一个元帅,要指挥一场战役,你怎么指挥?是不是只会下达一个简单的命令:第十四军必须在15日以前占领23号高地?至于十四军如何占领这个高地,兵力怎么部署、火力怎么配置、需要什么样的后勤资源……一堆的细节问题,你是不是只能忽略掉?
2、从“代码写给电脑看”到“代码是给人看”的转变。
在计算机发展的初期,程序非常的简单,电脑也无法理解高级的复杂的——实际上就是“类自然语言”的指令,程序员大量的工作是把需求“翻译”成电脑能够理解和执行的低级指令,比如石器时代的二进制打孔、汇编和C语言等等,形象的说就是“手把手”的教电脑如何操作,可以具体到“分配32个字节的内存”“存储到CPU的寄存器”这种粒度。
这种方式原始低效,根本无法满足日益增长的软件开发需求,一个最有效对接解决方式就是:把翻译(编译)的工作交给电脑自己去做,给程序员腾出时间和精力解决业务逻辑需求。所以,编程语言变得越来越“高级”越来越类似于人类自然语言。
其实,结构化编程的if...else...已经很接近人类语言了,但这还不够。于是,“面向对象”应运而生。语言是思维的载体:结构化语言,对应的仍然是具体的、一步一步执行性的思维;面向对象,对应的是抽象的、以目标为导向不论细节的的思维!
仍然以战役指挥为例,面向过程,大概就是:
- 32门火炮轰击地方阵地5分钟
- 16名士兵配合2辆坦克向前冲锋
- 1架直升机提供空中支援
- ……
面向对象就是:
第二连占领地方阵地。
怎么占领?第二连自己去实现!
于是很多初学者就接受不了,心里是悬着的,他老是要去想:第二连究竟是怎么占领这个阵地的呢?最关键的是,这个实现过程最后还是得他自己去写,所以他本能的就抗拒,或者说迷糊:进行面向对象的封装啊抽象啊啥的,脱了裤子放屁,多此一举嘛!O(∩_∩)O~
一不小心又写了这么多。但是呢,效果怎么样,我心里也是悬着的。所以,回到之前说的,我还是不建议初学者深究“面向对象”,以后,有了工作经验有了团队分工合作接触了大型项目,自然而然地就会逐渐明白:“面向对象”是被逼出来,而不是设计出来的!这一点,其实非常重要。
最后,给大家两种图:
还没有软装,等着加海报/壁画等……
++++++++++++++++++++
飞哥的“一起帮·源栈”http://ASP.NET全栈培训,小班教学,拎包入住。
开业酬宾,折上再打折,有兴趣的同学加QQ群:729600626,等着你来撩,^_^