前面《编程那些事儿》系列用了七篇文章,讲述了编程语言与面向对象编程相关的内容,本文从整体上做一个概括总结。希望能够用一个整体将面向对象编程思想和本质讲清楚。
抽象
抽象从两个方面来讲,一方面是计算机本身编程语言向人类文字靠近的一个进化方式,另一方面是我们开发人员将现实世界的事物信息化的第一步。
我们知道计算机本身只懂得一种语言就是二进制的0和1代码。人类通过数据二进制算法,首先对我们的文字符号二进制表示化,从某种意义上讲其实是二进制代码被通过一定的抽象用我们的语言文字符号表示的过程。
回看一下人类文字的起源与发展历史,我们就知道了抽象到底是怎么一回事了。最初人类为了记忆才发展出了文字,而最早的文字记录是通过在石头或者岩壁上刻一条条横线或者竖线来进行事件记录的。
最初的横线与竖线其实就是一种抽象,是对人类经历的事件在脑海中的记忆做标记的一种抽象。接着将一些事务通过画出大概的轮廓来表达,这是对复杂现实事务的抽象表示的开始,也就是象形文字最初的形成就是抽象,找出代表现实世界中事物的轮廓或者关键的特征然后抽象成符号记录下来。
象形符号逐渐加入了人的思考与内涵后,才有逐渐规范和抽象出我们使用的文字,这一点我们的中文汉字特别是古代文字最有代表性。
其实计算机本身就是靠电流的状态来表达信息,因为电流的最基本状态就两种,所以我们把它抽象成一个记录符号或者表达文字:0和1。
根据我们数学的二进制运算,我们能够将任何的数字,符号等找到一组对应的0和1组合的代码串。我们可以把计算机的语言文字进化想象成人类文字的进化,最开始的0和1类似我们的刻线记事。计算机的汇编符号语言类似我们的最初的象形符号,然后C/C++语言就类似我们现代的文字了。
不管是我们的现代文字还是计算机的机器代码,它们的目的就是通过一套思维逻辑规则表达我们现实世界的一切。
我们怎么用语言文字记录世界的呢? 统一的符号源自最初形状的抽象,符号附加人类想象的抽象就是文字。文字的不同组合描述世界。
我们的大脑反过来去读文字,其实就是一个编译解释的过程,这个过程可以理解成反抽象的过程,最终到达我们的大脑神经元中生物电流或者神经元对于那些最初统一形状或者轮廓特征的记忆积累。
计算机则是从0和1开始抽象出符号,从符号抽象出高级语言,用高级语言描述人类世界。反推过程就是我们用高级语言编写的内容,会被编译解释成低级的机器代码回归到计算机所能理解的0和1基元符号上。当然随着未来科技发展,特别是光子或者生物基元的表达肯定不止两种,如此会有新的进制来进行最基元的记忆处理。
回过头来说说抽象,面向对象可以说是人类认知思维跟计算机理解的世界的一个连接点。在这个连接点上,使用的思维逻辑更接近人类正常的思维模式。
我们要记忆某个东西,需要首先找到其标志性的特征,用这些标志性特征去描述它,这个过程就是抽象。
所以,我们在利用面向对象抽象过程中就是要去找我们要描述的事物的典型的标志性特征和行为,用它们来描述这个事物。
封装
封装其实也是我们人类日常处理事务的一个常用的思维方式,化繁就简,当我们面对纷乱繁杂的世界时,我们需要提高一下视角,从更宏观的角度去理清问题的主要脉络,这时候需要对一些相对的细节进行忽略,封装是为了更好的控制,更好的管理。如同我们平时的收纳,分门别类装箱处理。或链接装配,组合打包。
封装可以让繁杂变的简洁,让控制变的有效,让沟通变的简明。
继承和多态
我们的这个世界是一个分门别类的世界,或者说我们人类认知世界是从分门别类开始的。因为每一个物种都是经历了成千上万的进化,每一件物品都有这自己的生命周期,代次延续。
一个有生命的物种,一类无生命的物品,都有传承和创新。当我们去识别它们的类别,去描述它们的特征时,我们发现一个物种可能在不同的时空有共性又有差异。我们需要表现这种关系,因为整个世界都是这样一个世代一个世代延续下来的,我们每个世代都有与上一个世代相同不变的东西延续,又有新的东西产生发生了变化。
我们需要延续这种关联关系又需要呈现不同世代或周期里的不同物种的特征样态。
对应到编程描述世界的主题里,我们抽象封装的任何一个实体(包括数据对象,方法,参数,接口等等)都有状态和行为的不变与变化问题。
我们要定义这种关系,要展现在不同的时空里不同的样态,继承和多态就被发展了出来。
一个人在这个社会中会扮演很多中角色,每种角色都有自己的情景舞台,不管你登上多少个舞台,扮演过多少角色,最终你都是一个人。
在家庭里,你可能是父亲,是母亲,是儿子,是孙子等等,在单位里你可能是领导,是下属,是各种职员,在社区里,在俱乐部里,在马路上,在网络上等等,你都会因为所处的舞台环境不同,所扮演的角色不同展现出不同的你,你不会将单位里的角色属性放到家庭里,你也不会将社区里的角色和表现放到马路上。
但一系列的舞台,各种各样的角色,展现出各种各样的样态后,你还是你,一个人。所有角色的基础都是建立在你是一个人的基础上,不能换成一只狗。
这就是我们在面向对象编程设计时首先需要考虑的问题,那就是找到这个人,然后才能去定义后面的各种角色。定义的过程以及定义完成后他们之间展现出的关联性,你会发现继承是最好的概括。
拿Java语言体系来说,一切皆对象,Java世界中的那个人就是Object对象,后面定义的所有类型都是这个人在Java世界的不同舞台上扮演的各类角色,更有趣的是它允许开发人员去为这个人设置新的舞台,定义新的角色的样态和行为。
总结一下:面向对象编程思想和其抽象,封装,继承,多态四大原则,我们会发现它其实是我们人类世界的规则描述映射到了计算机世界里。
我们人类做事自古以来都是习惯从原点出发,一路走来的。面向对象编程也是如此,从最初的那个人,将它放到各种各样的舞台上,赋予给他各种角色,然后看他在这个舞台上的样态和行为,随着时空的转变会有怎样的改变,这些内容和过程就是我们需要去用代码描述的。
你有没有感觉到人类正在用对自己的认知创造一个新的世界,就是我们的网络世界。它会变的跟我们现实的世界越来越像,越来越融合,最终可能会合二为一。因为这两个世界进化的套路是一样的!
关于《编程那些事儿》系列文章,想用简单的语言来说一下我所理解的编程这件事儿,希望能够帮助到后来者,同时也对自己的学习做些梳理,纯属个人认知,水平有限,欢迎同行指正。
《编程那些事儿:告诉你程序员们从事的编程到底是在做什么》
《编程那些事儿:回到思维模型原点,看清纷杂的编程语言世界》
《编程那些事儿:为什么说抽象是面向对象编程的根基「I」?》
《编程那些事儿:面向对象编程基石之数据抽象(ADT)》
《编程那些事儿:对面向对象的封装与信息隐藏的一点思考》
《编程那些事儿:继承到底在面向对象编程里扮演什么样的角色呢》
《编程那些事儿:带你彻底理解面向对象编程的多态原则》