本文仅仅是面向个别同学的,可能存在xjb乱说的情况,如果有欢迎指出,不过我不喜欢谁喷我,谁喷我我就删掉,或者当没看见。
由于我才疏学浅,本文也就是对我所感受到的东西进行一些总结,估计很大概率会乱说,所以觉得有所了解的同学就不用看啦,反正也不会有收获的。
好了现在我们可以开始瞎掰了。
什么是面向对象?我稍微做了一下搜索,发现大多数人还是提到了经典的三个词:
封装、继承、多态
光是三个词还是不够,所以应该怎么理解这三个词呢?
所以我要开始瞎掰了。
就我认为的来看,面向对象更像是一种“划分方式”,就是一种指导你如何去划分你需要编写的程序的一种指导思路,方式就是把对象作为一个单位,对象,就像是现实生活当中的物体,这好像很显然。比如当我们要写一个程序去模拟你的家,你如何去划分呢?一个物件作为一个单位,好像真的是很显然的思路。
那么接下来来说说三个词,三个词其实更多的是说明了面向对象这种方式的特点。首先是封装,封装其实就是指我们在使用物品的时候,都是使用他提供给我们的功能(废话),比如我们使用电脑,进行开机,只需要按一下开机键(或者别的方法,反正不复杂对吧?),至于电路是如何运行的,内部的复杂原理我们都不需要知道,这就是封装的威力,就是说我们将对象内部的内容隐藏起来,只将提供的功能放出来,于是就有了一个好处:我们在划分一个程序的时候,在思考某一个内容的时候,可以认为另一个给我们提供功能的内容是可以信任的(毕竟我们无法知道内部原理,不能不信任,电脑开机的时候,如果不是体现出了问题,我们不会在开机前思考电脑是不是会出现电路问题之类的吧?),这样就使得我们划分变得容易,思考一个的时候另外一个可以不用考虑细节,避免一下考虑太多细节。
然后是第二个词,继承。其实这个词有许多可以讨论的地方,因为我渐渐发现,它似乎不是必须的。继承本身来说就是指在划分的时候体现的“是一个”的一种关系,这样使得我们的组织有一种明显的逻辑关系。比如诺基亚手机和三星手机都是手机,所以我们可以说,诺基亚手机和三星手机都继承于手机,他们都有是一个的关系,可是这样的好处是什么呢?由于他们这样的“是一个”的关系,他们之间是有很多想通的地方的,比如手机可以打电话,诺基亚手机和三星手机都可以打电话,那么如果我要写一个打电话的功能,由于他们不仅是有共同的功能,甚至有共同的属性(也就是所拥有的特性,或者说拥有的内容),也就是具有打电话模块,如果一个手机,用打电话模块可以有打电话功能,无论是诺基亚还是三星手机,都可以用打电话模块进行打电话,通过继承,我们可以直接使用手机的实现(用打电话模块进行打电话),于是他们实现相同,我就无需在每一个品牌手机上都进行实现,只需要通过继承来使用手机的通用的实现,这样使得我可以节约很多代码量。(所以说用代码行数来评价工作量的都是XX,毕竟我们总是在想方设法减少代码量。。)
这样就可以说到我们的第三个词了,多态。在刚才继承的例子中,我们知道了手机可以打电话,但是手机本身是不完整的,不具体的,如果说我现在需要完成一个功能,其中一个步骤需要用到一个“可以打电话的设备”进行打电话操作,这个时候,我们既可以使用诺基亚手机,也可以使用三星手机,于是无论我们使用哪个都可以,这样就增加了灵活性,因为我们可以这次使用诺基亚手机,下一次使用三星手机,他们可以无缝替换,使得一个模块和另外一个模块之间的耦合度降低,也就是说,一个模块和另外一个模块之间不存在太紧密的关系,这是我们所追求的,因为这样使得模块之间可以灵活的进行替换,或者改动而不影响另外一个。
所以说,这样三个词,组成了面向对象的“特点”。等等,我为什么要打引号?
既然是面向对象的特点,那么只要有面向对象就有这几种东西了?不一定吧,所以我打了引号。其中一个我想说的东西,就是继承。
其实我一直认为面向对象是很广的,只要是符合按照物件的方式去划分这种思路,应该都算,不必非得要这三个词都满足。
在说到其他东西之前,让我们来聊聊几种面向对象
这是一种传统意义上的面向对象,代表人物:java
, c++
, python
,这应该都是大家非常熟悉的语言了。
什么是类?对象我们知道了,就是物件,就是物体,是具体的桌子椅子,类,就是他们的集合,就是桌子这个说法,就是椅子这个说法,是抽象的,是所有桌子共有的。为什么要这样来划分?因为有我们来说某一个桌子的时候,他总是所有桌子中的某一个,我们把所有桌子的特性都描述清楚,那么等到需要创建某一个的时候,只需要做少量的改变,把仅属于这个桌子的特性给出来,就可以指定这一个桌子了。
这种方式就像是,指定了一个桌子所具有的东西,和一般一个桌子完成这些功能的方式,然后我给出这个桌子的名字(假设一个桌子有名字?),然后一个桌子就造出来了。
这就是Javascript
的方式。其实我并没有太多的资格来说明这种方式,我对Javascript
实在是不是很熟悉,不过简短的说,这种方式就好像是,我现在想要一个桌子,可是以前从来没有过桌子这种东西,但是有椅子,于是我克隆了一个椅子,把椅子和桌子不一样的地方都给改掉,于是我得到了一个桌子。等到什么时候我又需要一个桌子,我就不需要再从一个椅子克隆来了,我直接克隆之前的那个桌子,于是我得到了又一个桌子。
在这个例子当中,第一个桌子的原型是椅子,第二个及以后的桌子的原型就是那第一个桌子,于是他们形成了一个“链”,就叫做原型链,在这种情况下,桌子和椅子共有的部分,其实是在椅子上的,而给人一种桌子自己也有的感觉,是因为当在桌子这个东西上找某个特性上找不到的时候,就会去他的原型上找,直到找到,找不到就会报错。
最后我来留一个悬念,还有什么样的方式呢?
好了,我们现在可以看到继承的“必要性”了,因为到目前位置,我们就已经看到基于原型的方式的面向对象,并没有使用继承的方式。虽然他通过自己的方式达到了差不多的效果,但是其实严格来说是没有使用继承的,于是,我们知道了继承并不是必须的。
接下来就要来说说我真正想说的东西了,interface,或者更严格来说,trait(虽然我还不太明白它俩具体的差别)。
熟悉java
的同学应该知道interface
这个东西,简单的说,接口,规定了一个对象需要满足的功能,对了,我们是不是想起了多态?多态就是通过规定了功能,但是不规定实现细节来完成的!所以,我们并不是很需要继承呀?之前我们看到的多态,可以通过继承的方式来做到,现在我们有了接口,只要能够指定接口,也可以完成多态!可是,问题又来了,继承还有一个优势,方法复用!方法复用,也就是指我们所继承的东西,他实现的可以由继承者使用,使得我们只需要实现一次,那么trait
或者说interface
又怎么做到呢?
于是我们需要一个机制来做到,这就是Rust
的方式。Rust
使用了trait
作为接口,但是!但是trait
还有一个很重要的东西,他能够继承!我们不是说不用继承嘛?这里的继承可不和类那样的继承相同,这里的继承是指,一个trait
需要另外一个trait
先被满足,才可以被满足,于是我们就可以!使用!那个依赖的trait
了!现在,我们就可以提供默认的方法了,于是只要实现这个trait
,只要不特殊声明,我们可以就可以通过默认实现的方法来做到类似于继承的效果啦!
这篇文章主要提了一下Rust
的用trait
来代替继承完成的面向对象的方法,说明了继承的灵活实现方法。其他想到要补充的,就随时想到再补充啦。