前排提示:本章节适合对面对对象编程的语法有些了解但是对思维方式迷惑的人,如果是小白请移步:https://blog.csdn.net/u011471253/article/details/104020182
面对对象的基本思想就是信息的交流以及对象的层级关系。一切思维方式都会围绕着信息的交流以及对象层级的建立展开,这也可以解释为何许多的设计模式中会间接地调用自己的方法(仲裁者模式),目的就是为了使信息可以传递出其,好让第三方也可以参与信息的处理。由于这种设计理念的存在面对对象编程非常适合团队的分工协作。(当然蹩脚的程序员将会拿他写面对过程程序,使对象关系变得复杂,这样就不适合团队协作了。这是一个例外不是吗?)
现在我们首先关注面对对象的最表层的东西——对象,嗯,对象的层级关系(有关对象请去https://blog.csdn.net/u011471253/article/details/104018736)。第一点就是父子关系,也可以称之为继承关系。子类可以默认赋值给父类类型的变量,反之需要强制类型转换。因为父类拥有的方法子类通过继承一定会拥有,所以如果某处代码调用了一个父类变量但是它指向的是一个子类对象也不会有什么大的问题,因为所有的父类方法子类都有不会出现调用了一个父类方法然后报错的情况(前提是你的方法本身已经写对了),反之如果一个子类变量指向了一个父类对象,那么当某一处代码调用子类方法的时候可能会产生方法缺失(子类的某些方法父对象可能没有),此时为了程序安全(防止调用不存在的方法)编译器便会提前报错,提示你要加强制类型转换。所谓强制类型转换其实就是将父对象相比子对象缺失的那一部分方法补齐(此时的父对象与一个子对象无异,此后的处理便会把这个对象当做子对象处理)。
利用以上性质我们就可以通过层级降低代码的冗杂度,我们将相同的方法定义在父类中然后将不同的方法定义在不同的子类中,这样每个子类就不用再编写那先相同的部分了。而且父变量可以指向子变量也有助于使用时的归一化处理(统一处理)。例如我们要定义一群游戏“英雄”对象,因为他们的技能不同自然需要不同的特效处理方法去处理,但是他们却都有血量这个属性以及“平A”这个方法所以我们可以定义一个类里面有一个“血量”属性和一个“平A”方法,并将这个类看作父类,让具体的英雄的类作为子类继承“英雄”这个父类,那么就算这些作为子类的英雄(具体英雄)就算一句代码也不写也会拥有继承自父类的“血量”属性和“平A”方法。例如我编写了一个叫“阿狸”的类,并让它作为子类继承“英雄”这个父类,那么就算我在“阿狸”类中一句代码也不写,这个类也具有“血量”属性和“平A”方法。然后我再添加一些其他的英雄的类,同理这些类只要继承了父类“英雄”便都会就有“血量”属性和“平A”方法,而不需要添加一句代码。看,如此以来所有英雄子类都可以省掉一些共有的继承自“英雄”父类的代码,所以这种特性可以降低冗杂度。
降低冗杂度我们是看出来了,那么为什么这种机制可以方便管理呢?试想,如果我们相对这些不同英雄类的对象进行管理那么因为这些英雄来自不同的类,所以我们不得不用不同的(相对应的)类型来定义变量进行处理。例如如果我想对“阿狸”这个类进行处理那么我需要这样写:
阿狸 A =new 阿狸();
A.平A();
刚才我们先生成了一个“阿狸”类型的对象赋给了“阿狸”类型(就类似于int类型之类的,仅仅是一种数据类型而已)的变量A,然后调用了它的方法“平A”。此时此刻还没有什么问题,但是如果我想用“诺手”类怎么办?最容易想到的是,我们需要修改原有的代码改成下面这样:
诺手 A =new 诺手();
A.平A();
刚才我们先生成了一个“诺手”类型的对象赋给了“诺手”类型(就类似于int类型之类的,仅仅是一种数据类型而已)的变量A,然后调用了它的方法“平A”。好的问题出现了,如果一共有成百上千个英雄类我都想试试呢?或者我想支持在线选择,而且支持鼠标右键攻击呢?最容易想到的是定义成百上千个不同类型的变量,这可真是累人。现在是时候使用“继承”这个特性来加强管理了!我们只需要这样:
英雄 A=new 阿狸();
A.平A();
即可,此时我们只需要将new 阿狸()这一部分作为参数由外部传入(在线选择)作为变量B那么无论此时B是“阿狸”型还是“诺手”型对象都可以赋给英雄型变量A,而且可以成功调用他们的共有方法“平A”。这样一来就可以对共有部分进行统一化管理而不需要每一种写一个,这样不但冗杂而且当想修改一下“平A”(所有英雄平A的相同部分)的时候就不得不把每一种英雄的代码都改一遍,但是如果使用以上方式就可以实现只改一处代码就可以实现相同的改动。