iOS面向对象三大特性 封装性 继承性 多态性

356 阅读6分钟

封装

封装: 屏蔽内部实现的细节, 仅仅对外提供共有的方法/接口

  • 类是数据与功能的封装,数据就是成员变量,功能就类方法或对象方法

  • 对数据的封装,也就是对成员变量的封装

  • 不封装的缺点:当一个类把自己的成员变量暴露给外部的时候,那么该类就失去对该成员变量的管理权,别人可以任意的修改你的成员变量。

  • 不封装的优点: 将变化隔离,提高安全性。

  • 封装就是将数据隐藏起来,只能用此类的方法才可以读取或者设置数据,不可被外部任意修改是面向对象设计本质。这样降低了数据被误用的可能性 ,提高代码的灵活性!

  • 原则

    • 将不需要对外提供的内容都隐藏起来,把属性都隐藏,提供公共的方法对其访问

     规范: 一般情况下不会对外直接暴露成员变量, 都会提供一些共有的方法进行赋值

           成员变量都需要封装起来

继承

只要A类继承了B类, 那么A类就拥有了B类的所有属性和方法(对象方法和类方法)

语法:@interface 类名 : 需要继承的类

优点:

     提高代码的复用性

     可以让类与类之间产生关系, 正是因为继承让类与类之间产生了关系所以才有了多态

注意: 

  • 不要以为继承可以提高代码的复用性, 以后但凡发现多个类当中有重复代码就抽取一个父类

    只要满足一定的条件我们才能使用继承

    条件: XXXX 是 XXX   /    某某某 is a 某某某

  • 在继承中方法可以重写, 但是属性(成员变量)不能重写,因为子类继承父类,子类将会拥有父类的所有成员变量,若在子类中定义父类同名成员变量 属于重复定义

    如果子类中有和父类中同名的方法, 那么我们称之为方法重写

  • 继承中的方法调用顺序, 如果自己有就调用自己的, 如果自己没有就调用父类的

方法的调用顺序, 先自己再父类, 如果父类中没有再爷爷类, 如果爷爷类再没有就找爷爷的爸爸类

如果一直找到NSObject类都没有找到, 那么就会报错

reason: '-[Iphone signalWithNumber:]: unrecognized selector sent to instance 0x1003043c0'

缺点:

     耦合性太强(依赖性太强,不能没有父类)

多态

多态:父类指针指向子类对象

  • 多态的条件

    • 有继承关系

    • 子类重写父类方法

    • 父类指针指向子类对象

    动物 *a = [猫 new];

  • 表现:当父类指针指向不同的对象的时候,通过父类指针调用被重写的方法的时候,会执行该指针所指向的那个对象的方法

  • 多态的优点

    • 多态的主要好处就是简化了编程接口。它允许在类和类之间重用一些习惯性的命名,而不用为每一个新的方法命名一个新名字。这样,编程接口就是一些抽象的行为的集合,从而和实现接口的类的区分开来。
    • 多态也使得代码可以分散在不同的对象中而不用试图在一个方法中考虑到所有可能的对象。 这样使得的代码扩展性和复用性更好一些。当一个新的情景出现时,无须对现有的代码进行改动,而只需要增加一个新的类和新的同名方法。

多态的原理

  • 动态绑定:

    • 动态类型能使程序直到执行时才确定对象的真实类型
    • 动态类型绑定能使程序直到执行时才确定要对那个对象调用的方法,编译时根据直接的对象类型判断语法正确与否 Animal *a1 = [Dog new];

    [a1 eat];

编译看Animal有没有eat方法,运行看Dog有没有eat方法(有就执行Dog的eat方法,没有就执行Animal的eat方法)

  • OC不同于传统程序设计语言,它可以在运行时加入新的数据类型和新的程序模块:动态类型识别,动态绑定,动态加载

  • 如果存在多态,父类是可以访问子类特有的方法,必须强制类型转换为子类才能调用

假设 子类 Dog 有一个特有的方法bark
[dog bark];
Animal *an2 = [Dog new];
[(Dog*)an2 bark]; //把父类的指针,强制类型转换

id数据类型

  • 静态类型

    • 将一个指针变量定义为特定类的对象时,使用的是静态类型,在编译的时候就知道这个指针变量所属的类,这个变量总是存储特定类的对象。
Person *p = [Person new];
  • 动态类型

    • 这一特性是程序直到执行时才确定对象所属的类

id obj = [Person new];

  • id 是一种通用的对象类型,它可以指向属于任何类的对象,也可以理解为万能指针 ,相当于C语言的 void *

    因为id是动态类型,所以可以通过id类型直接调用指向对象中的方法(可以调用子类特有的方法,可以调用私有方法), 编译器不会报错

 id obj = [Cat new];
 
 [obj eat]; // 不用强制类型转换
 [obj test]; //可以调用私有方法
  • id类型不能使用.语法, 因为.语法是编译器特性, 而id是运行时特性

  • 虽然说id数据类型可以存储任何类型的对象,但是不要养成滥用这种通用类型

    • 如没有使用到多态尽量使用静态类型

      为了避免动态数据类型引发的运行时的错误, 一般情况下如果使用动态数据类型定义一个变量, 在调用这个对象的方法之前会进行一次判断, 判断当前对象是否能够调用这个方法

    • 静态类型可以更早的发现错误(在编译阶段而不是运行阶段)

    • 静态类型能够提高程序的可读性

    • 使用动态类型前最好判断其真实类型

  • 动态类型判断类型

    - (BOOL)isKindOfClass:classObj 判断实例对象是否是这个类或者这个类的子类的实例

    - (BOOL) isMemberOfClass: classObj 判断是否是这个类的实例

    + (BOOL) isSubclassOfClass:classObj 判断类是否是指定类的子类