隔壁小孩也能看懂的面向对象(概念篇)

不少初学者在听到【面向对象】这个名词的时候挺懵逼,别惧怕,它只是听起来很厉害的样子~编程

什么是面向对象

下面我举个栗子,你们来思考下该如何设计程序~函数

一个神秘组织的boss想玩五子棋了,任命你来开发。这个时候你就开始头脑风暴,脑海里复盘本身曾经晚自习上和同桌小哥哥下过的五子棋。咱们脑海里有这样一个过程:布局

    1. 开始游戏
    1. 黑子先走
    1. 绘制画面
    1. 判断输赢
    1. 轮到白子
    1. 绘制画面
    1. 判断输赢
    1. 返回步骤2
    1. 输出最后结果

而后再用函数将上面每一个步骤实现,这个游戏就设计好了~~~~设计

嗯嗯,看上去好像没什么问题,但这个时候boss说他想玩的不得了,给你加了个小弟一块儿开发,你说我来搞黑子,你来搞白子,最后咱们再来和一下,小弟说o**k。3d

正在你和小弟背靠背埋头开发的时候,boss来转了一圈,大喊一句:“你俩咋在写一样的代码?”cdn

这时你发现,对象

    1. 黑子和白子的行为是如出一辙的
    1. 负责绘制画面的可交由棋盘系统
    1. 负责断定犯规、输赢的可交由规则系统

这个时候你和小弟说,咱们搞三个对象:blog

“第一类玩家对象 负责接收用户输入,并告知第二类棋盘对象 起子布局的变化,棋盘对象接收到了棋子的变化就要负责在屏幕上面显示出这种变化,同时利用第三类规则对象来对棋局进行断定。”继承

小弟一据说要搞对象立刻重振旗鼓开始开发~~接口

好了,故事讲到这里,咱们其实就已经了解两种设计思想:

最开始你分析出解决问题所须要的步骤,而后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用的思想,就是【面向过程】

后来你把构成问题事务分解成各个对象,创建对象的目的不是为了完成一个步骤,而是为了描述某个事物在整个解决问题的步骤中的行为,咱们用个高大上的名词包装下,称之为【面向对象】

2、面向对象的三大特征

虽然咱们完成了boss的五子棋设计,但更多的时候,咱们涉及的对象却远远不止三个。这个时候咱们就要对对象、对象之间的关系进行设计~

面向对象有三大特征:封装,继承,多态

听起来好高大上有木有,惧怕你就输了~~~

封装

封装就是把客观事物封装成抽象的类,而且类能够把本身的数据和方法只让可信类或者对象操做,对不可信的进行信息隐藏。

概念听起来比抽象自己还抽象,仍是再举个栗子吧。

在咱们平常聊天的时候,常常会说“这类人如何如何”、“那类怎样怎样”,若是你说过,那恭喜你,你已经知道什么是抽象了!

咱们将不一样的客观事物的共同点提取出来,它们的共同点能够是一些特征,也能够是都能完成的事情。

想一想你的boss和小弟boy的共同点:

    1. 他们都是人类
    1. 他们都会下五子棋

那么咱们能够抽象出一个 player 类,player类的属性是person,具备的方法是canPlay。若是有一天你对着神秘组织的人员名单找player,保证你名单翻来覆去找几遍都找不到,由于没有人叫player啊!player只是一个类,而boss和boy才是实现了这个类的实例对象。

继承

简单来讲,咱们如今已经有个player类了,player类的属性是person,方法是canPlay。后来你仔细一想,发现事情并不简单,别的组织会下五子棋的人竟然也在这个类里面!这可不行,要知道你所在的神秘组织除了person属性、canPlay方法之外,还有beauty属性、canPlayGood方法。因而你打算搞个特别点的类,叫greatPlayer类。这个时候难道要从新写以前的player类的方法吗?nooooooo,咱们所作的一切努力都是为了堵住那一句:“咋在写一样的代码?”

继承,就是使用现有类的全部功能,并在无需从新编写原来的类的状况下对这些功能进行拓展。

而继承有两种实现方式:“继承”(Inheritance)和“组合”(Composition)。

首先咱们要明白,组合和继承都是提升代码可重用性的手段。区别是在设计对象模型时,若是去划分类和类之间的关系。说白了就是如何对类和类进行拓展和复用。

继承:就是 is a的关系,好比说student继承person,则说明student is a person。

组合:设计类的时候把要组合的类的对象加入到该类中做为本身的成员变量。

好比说,若是发现两个类具备不少相同的方法,很类似须要抽象:

好比上图A,B两个类中method1,method2和method3三个方法都相同,

继承的抽象方式是:

组合的抽象方式是:

下面咱们来比较下组合和继承的优缺点:

继承

优势:

  • 子类能够重写父类的方法来方便地实现对父类的扩展。

缺点:

  • 父类的内部细节对子类是可见的。这太不符合“你办事我放心”的想法了。

  • 若是对父类方法作了修改,子类的方法必须作出相应的修改。因此子类和父类是一种高耦合。

组合

优势:

  • 被包含的对象的内部细节对当前对象不可见,“你办事我放心”~

  • 当前对象与被包含的对象是一个低耦合关系,修改包含对象的类代码不须要修改当前对象类的代码~

缺点:

  • 容易产生过多对象

  • 为了能组合多个对象,必须对【接口】进行定义

因此,组合比继承更具备灵活性和稳定性,在设计的时候优先使用组合~

多态

多态的定义是同一个操做,做用在不一样的对象上,能够产生不一样的解释和不一样的执行结果。

对于强类型语言,一般采用抽象类或者接口,进行更高一层的抽象,从而直接使用更高层的抽象。就比如强类型语言中里,有两个方法:int和int相加,float和float相加,既然都要相加,那就再抽象一下。实际上就是为了弱化具体的类型。

而对于像js这种弱类型语言来讲,多态就是与生俱来的。

再来看多态的两种实现方式:覆盖重载

覆盖:子类从新定义父类的方法。咱们的js原型链继承那套,不就是覆盖了吗~

重载:容许存在多个同名函数,而这些函数的参数表不一样(或许参数个数不一样,或许参数类型不一样,或许二者都不一样)

重载的话,像js确实没有,毕竟是弱类型语言。顺便一提,重载的概念并不属于“面向对象编程”,重载的实现是:编译器根据函数不一样的参数表,对同名函数的名称作修饰,而后这些同名函数就成了不一样的函数(对编译器)

有两个同名函数:function func(p:integer):integer;和function func(p:string):integer;。那么编译器作过修饰后的函数名称多是这样的:int_func、str_func

对于这两个函数的调用,在编译器的时候就已经肯定了,是静态的,其地址在编译器就绑定了。因此重载和多态无关。

而js自己是解释型语言而非编译型语言,因此确定和重载不要紧。

接口

刚刚咱们说了,为了能组合多个对象,必须对【接口】进行定义。

那么接口究竟是什么呢?

接口提供了一种用来讲明一个对象应该具备哪些方法的手段。它能够代表这些方法的含义,可是却不包含具体的实现。我规定了你要作什么,可是你怎么作我可无论~

如今咱们知道接口是什么了,可是为毛要用接口呢?

有了接口,咱们就能够按对象提供的特性对它们进行分组。再再再举个栗子,如今有对象A、对象B以及接口I,即使对象A和对象B的差别巨大,但只要它们都实现了接口I,那么在A.I(B)方法中,就能够互换使用A和B,好比B.I(A)。那不是很爽吗!我能够互换使用A、B的方法了!

另外,还可使用接口开发不一样的类的共同性。若是把本来要求以一个特定的类为参数的函数改成要求以一个特定的接口为参数的函数,那么全部实现了该接口的对象均可以做为参数传递给它,这样作的话,明明彼此不相关的对象,也能够被相同地对待使用该方法了!

结语

面向对象是一门很是实用的设计思想,本文旨在让隔壁小孩也能看懂,若是内容有误欢迎在评论区吐槽~

相关文章
相关标签/搜索