IOS设计模式的六大设计原则之里氏替换原则(LSP,Liskov Substitution Principle)
2014-05-01 23:15
357 查看
转:点击打开链接
定义
里氏替换原则的定义有两种,据说是由麻省理工的一位姓里的女士所提出,因此以其名进行命名。
定义1:如果对一个类型为T1的对象o1,都有类型为T2的对象o2,使得以T1所定义的程序P中在o1全都替换成o2时,程序的行为不发生任何变化,那么T2为T1的子类。
定义2:所有引用父类的地方都必须能够透明地使用其子类对象。
定义解读
其实两个定义所表达的意思都相同,就是在所有父类出现的地方,子类都可以出现,并且将父类对象替换为子类对象的时候,程序不会抛出任何异常或者错误,因此我们需要注意的是,尽量不要重载或者重写父类的方法(抽象方法除外),因为这样可能会改变父类原有的行为。
优点
代码共享,减少创建类的工作量,每个子类都拥有父类的所有属性和方法;
提高代码的可重用性;
提高代码的可扩张性;
提高产品或项目的开放性。
缺点
继承是入侵性的,拥有父类的属性和方法;
降低代码的灵活性,必须拥有父类的属性和方法;
增强耦合性,父类属性或方法改变,需要考虑子类。
问题提出
有一功能P1,由类A完成。现需要将功能P1进行扩展,扩展后的功能为P,其中P由原有功能P1与新功能P2组成。功能P由类A的子类B来完成,则子类B在完成新功能P2的同时,有可能会导致原有功能P1发生故障。
解决方案
当使用继承时,遵循里氏替换原则。类B继承类A时,除添加新的方法完成新增功能P2外,尽量不要重写父类A的方法,也尽量不要重载父类A的方法。
继承包含这样一层含义:父类中凡是已经实现好的方法(相对于抽象方法而言),实际上是在设定一系列的规范和契约,虽然它不强制要求所有的子类必须遵从这些契约,但是如果子类对这些非抽象方法任意修改,就会对整个继承体系造成破坏。而里氏替换原则就是表达了这一层含义。
继承作为面向对象三大特性之一,在给程序设计带来巨大便利的同时,也带来了弊端。比如使用继承会给程序带来侵入性,程序的可移植性降低,增加了对象间的耦合性,如果一个类被其他的类所继承,则当这个类需要修改时,必须考虑到所有的子类,并且父类修改后,所有涉及到子类的功能都有可能会产生故障。
示例
还是继续我们上面的场景:这里,我们将Employee类作为父类,它里面有一个计算工资的方法calculateSalary,代码如下所示:
.h文件:
.m文件:
调用代码:
输出结果如下:
2013-11-26 16:03:37.058 LiskovSubstitutionPrinciple[3305:303] 张三的工资是100
现在我们为Employee类添加一个子类总监Director类,该类新增了一个职责说明的方法和重写了calculateSalary方法,如下所示:
调用代码:
输出结果如下:
2013-11-26 16:15:19.886 LiskovSubstitutionPrinciple[3429:303] 总监张三的工资是10000
从上面的结果我们可以看到,由于重写了父类Employee的calculateSalary方法,造成计算薪资的方法都是调用子类Director重写后的方法。如果应用场景是要求公司的薪资都是统一的,那么调用Director类重写的方法就是不正确的。如果非要重写父类里面的方法,比较通用的做法是:原来的父类和子类都继承一个更通用的基类,原有的继承关系去掉,采用依赖、聚合、组合等关系代替。
里氏替换原则通俗的来讲就是:子类可以扩展父类的功能,但不能改变父类原有的功能。它包含以下2层含义:
子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法;
子类中可以增加自己特有的方法。
在项目中所有使用子类的地方都可用父类替换,但在调用方法的时候,即呈现面向对象编程的多态性。里氏替换原则,是非常重要的原则,也是相对较难的原则
源码下载
定义
里氏替换原则的定义有两种,据说是由麻省理工的一位姓里的女士所提出,因此以其名进行命名。
定义1:如果对一个类型为T1的对象o1,都有类型为T2的对象o2,使得以T1所定义的程序P中在o1全都替换成o2时,程序的行为不发生任何变化,那么T2为T1的子类。
定义2:所有引用父类的地方都必须能够透明地使用其子类对象。
定义解读
其实两个定义所表达的意思都相同,就是在所有父类出现的地方,子类都可以出现,并且将父类对象替换为子类对象的时候,程序不会抛出任何异常或者错误,因此我们需要注意的是,尽量不要重载或者重写父类的方法(抽象方法除外),因为这样可能会改变父类原有的行为。
优点
代码共享,减少创建类的工作量,每个子类都拥有父类的所有属性和方法;
提高代码的可重用性;
提高代码的可扩张性;
提高产品或项目的开放性。
缺点
继承是入侵性的,拥有父类的属性和方法;
降低代码的灵活性,必须拥有父类的属性和方法;
增强耦合性,父类属性或方法改变,需要考虑子类。
问题提出
有一功能P1,由类A完成。现需要将功能P1进行扩展,扩展后的功能为P,其中P由原有功能P1与新功能P2组成。功能P由类A的子类B来完成,则子类B在完成新功能P2的同时,有可能会导致原有功能P1发生故障。
解决方案
当使用继承时,遵循里氏替换原则。类B继承类A时,除添加新的方法完成新增功能P2外,尽量不要重写父类A的方法,也尽量不要重载父类A的方法。
继承包含这样一层含义:父类中凡是已经实现好的方法(相对于抽象方法而言),实际上是在设定一系列的规范和契约,虽然它不强制要求所有的子类必须遵从这些契约,但是如果子类对这些非抽象方法任意修改,就会对整个继承体系造成破坏。而里氏替换原则就是表达了这一层含义。
继承作为面向对象三大特性之一,在给程序设计带来巨大便利的同时,也带来了弊端。比如使用继承会给程序带来侵入性,程序的可移植性降低,增加了对象间的耦合性,如果一个类被其他的类所继承,则当这个类需要修改时,必须考虑到所有的子类,并且父类修改后,所有涉及到子类的功能都有可能会产生故障。
示例
还是继续我们上面的场景:这里,我们将Employee类作为父类,它里面有一个计算工资的方法calculateSalary,代码如下所示:
.h文件:
@interface Employee : NSObject // 计算工资 - (void)calculateSalary:(NSString *)name; @end
.m文件:
#import "Employee.h" @implementation Employee - (void)calculateSalary:(NSString *)name { NSLog(@"%@的工资是100",name); } @end
调用代码:
//调用Employee类的calculateSalary方法 Employee *employee = [[Employee alloc] init]; [employee calculateSalary:@"张三"]; [employee release];
输出结果如下:
2013-11-26 16:03:37.058 LiskovSubstitutionPrinciple[3305:303] 张三的工资是100
现在我们为Employee类添加一个子类总监Director类,该类新增了一个职责说明的方法和重写了calculateSalary方法,如下所示:
#import "Director.h" @implementation Director - (void)calculateSalary:(NSString *)name { NSLog(@"总监%@的工资是10000",name); } - (void)duty { NSLog(@"总监的职责是管理"); } @end
调用代码:
Employee *employee = [[Director alloc] init]; //将所有父类出现的地方都替换成子类 [employee calculateSalary:@"张三"]; [employee release];
输出结果如下:
2013-11-26 16:15:19.886 LiskovSubstitutionPrinciple[3429:303] 总监张三的工资是10000
从上面的结果我们可以看到,由于重写了父类Employee的calculateSalary方法,造成计算薪资的方法都是调用子类Director重写后的方法。如果应用场景是要求公司的薪资都是统一的,那么调用Director类重写的方法就是不正确的。如果非要重写父类里面的方法,比较通用的做法是:原来的父类和子类都继承一个更通用的基类,原有的继承关系去掉,采用依赖、聚合、组合等关系代替。
里氏替换原则通俗的来讲就是:子类可以扩展父类的功能,但不能改变父类原有的功能。它包含以下2层含义:
子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法;
子类中可以增加自己特有的方法。
在项目中所有使用子类的地方都可用父类替换,但在调用方法的时候,即呈现面向对象编程的多态性。里氏替换原则,是非常重要的原则,也是相对较难的原则
源码下载
相关文章推荐
- IOS设计模式的六大设计原则之单一职责原则(SRP,Single Responsibility Principle)
- IOS设计模式的六大设计原则之单一职责原则(SRP,Single Responsibility Principle)
- iOS7 NSURLSession
- iOS学习笔记10(7)—GCD示例源码
- iOS学习笔记10(7)—GCD示例源码
- ios 实现引导页面效果
- 开源一个C#写的Android和IOS都能跑的 打击感强的RPG玩玩。
- 可变数组NSMutableArray声明时的问题
- IOS中类和对象还有,nil/Nil/NULL的区别
- IOS中类和对象还有,nil/Nil/NULL的区别
- Use GraceNote SDK in iOS(二)获取音乐的完整信息
- iOS消息推送机制的实现
- iOS消息推送机制的实现
- iOS 基础类解析 - NSCharacterSet
- hdu A Mathematical Curiosity
- ios 实现版本更新检查
- CCNP TSHOOT (三) Cisco IOS 软件维护和排障笔记
- iOS7下滑动返回与ScrollView共存二三事
- iOS开发 -- KeyChain使用与共享数据
- iOS手势识别的详细使用(拖动,缩放,旋转,点击,手势依赖,自定义手势)