深入浅出设计模式原则之里氏代换原则(Liskov Substitution Principle)
下面以“几维鸟不是鸟”为例来说明里氏替换原则(程序源码)。
#include <QCoreApplication>
#include <iostream>/*!* \brief 鸟类*/
class Bird{
public:double _fly_speed;void SetSpeed(double speed){_fly_speed = speed;}double GetFlyTime(double distance){return (distance/_fly_speed);}
};/*!* \brief 燕子类*/
class Swallow:public Bird{};/*!* \brief 几维鸟类*/
class BrownKiwi:public Bird{
public:void SetSpeed(double speed){_fly_speed = 0;}
};int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);Swallow *bird1 = new Swallow;bird1->SetSpeed(120);std::cout<<bird1->_fly_speed<<std::endl;std::cout<<bird1->GetFlyTime(300)<<std::endl;BrownKiwi *bird2 = new BrownKiwi;bird2->SetSpeed(120);std::cout<<bird2->_fly_speed<<std::endl;std::cout<<bird2->GetFlyTime(300)<<std::endl;return a.exec();
}
运行结果:
120
2.5
0
inf
分析:鸟一般都会飞行,如燕子的飞行速度大概是每小时 120 千米。但是新西兰的几维鸟由于翅膀退化无法飞行。假如要设计一个实例,计算这两种鸟飞行 300 千米要花费的时间。显然,拿燕子来测试这段代码,结果正确,能计算出所需要的时间;但拿几维鸟来测试,结果会发生“除零异常”或是“无穷大”,明显不符合预期,其类图如图 1 所示。
图1 “几维鸟不是鸟”实例的类图
程序运行错误的原因是:几维鸟类重写了鸟类的 setSpeed(double speed) 方法,这违背了里氏替换原则。
解决方法:
取消几维鸟原来的继承关系,定义鸟和几维鸟的更一般的父类,如动物类,它们都有奔跑的能力。几维鸟的飞行速度虽然为 0,但奔跑速度不为 0,可以计算出其奔跑 300 千米所要花费的时间。其类图如图 2 所示。
#include <QCoreApplication>
#include <iostream>/*!* \brief 动物类*/
class Animal{
public:double _run_speed;void SetRunSpeed(double speed){_run_speed = speed;}double GetRunTime(double distance){return (distance/_run_speed);}
};/*!* \brief 鸟类*/
class Bird:public Animal{
public:double _fly_speed;void SetSpeed(double speed){_fly_speed = speed;}double GetFlyTime(double distance){return (distance/_fly_speed);}
};/*!* \brief 燕子类*/
class Swallow:public Bird{};/*!* \brief 几维鸟类*/
class BrownKiwi:public Animal{};int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);Swallow *bird1 = new Swallow;bird1->SetSpeed(120);std::cout<<bird1->_fly_speed<<std::endl;std::cout<<bird1->GetFlyTime(300)<<std::endl;BrownKiwi *bird2 = new BrownKiwi;bird2->SetRunSpeed(120);std::cout<<bird2->_run_speed<<std::endl;std::cout<<bird2->GetRunTime(300)<<std::endl;return a.exec();
}
运行结果:
120
2.5
120
2.5
里氏替换原则通俗来讲就是:子类可以扩展父类的功能,但不能改变父类原有的功能。也就是说:子类继承父类时,除添加新的方法完成新增功能外,尽量不要重写父类的方法。
根据上述理解,对里氏替换原则的定义可以总结如下:
- 子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法
- 子类中可以增加自己特有的方法
- 当子类的方法重载父类的方法时,方法的前置条件(即方法的输入参数)要比父类的方法更宽松
- 当子类的方法实现父类的方法时(重写/重载或实现抽象方法),方法的后置条件(即方法的的输出/返回值)要比父类的方法更严格或相等
参考
- 设计模式六大原则(2):里氏替换原则
- 里氏替换原则——面向对象设计原则
深入浅出设计模式原则之里氏代换原则(Liskov Substitution Principle)相关推荐
- 设计模式-设计原则之里氏代换原则
设计原则之里氏代换原则 里氏代换原则 案例(正方形不是长方形) 案例改进 里氏代换原则 里氏代换原则是面向对象设计的基本原则之一. 里氏代换原则:任何基类可以出现的地方,子类一定可以出现. 通俗理解: ...
- 带你认识六种设计原则(开闭原则、里氏代换原则、依赖倒转原则....)
前言 1. 设计原则 1.1. 开-闭原则 1.2. 里氏代换原则 1.3. 依赖倒转原则 1.4. 接口隔离原则 1.5. 合成/聚合原则 1.6. 迪米特法则 前言 学习设计模式之前先要了解其中的 ...
- Java设计原则之单一职责原则、开闭原则、里氏代换原则
文章目录 面向对象设计原则概述 单一职责原则 开闭原则 里氏代换原则 面向对象设计原则概述 软件的可维护性(Maintainability)和可复用性(Reusability)是两个非常重要的用于衡量 ...
- 设计原则 单一职责原则、开放封闭原则、依赖倒置原则、里氏代换原则、迪米特法则
目录 1 单一职责原则 2 开放封闭原则 3 依赖倒置原则 4 里氏代换原则 5 迪米特法则 1 单一职责原则 比如:电脑内存坏了就应该更换内存,不应该更换CPU (内存负责内存.CPU负责CPU) ...
- 依赖倒转原则和里氏代换原则详解
初学依赖倒转原则和里氏代换原则时,由于笔者水平有限,并没有看懂书上的专业术语的解释,经过反复摸索和学习,发现里氏代换原则和依赖倒转原则可以一言以蔽之: 里氏代换原则:开发时以抽象为核心,针对抽象编程, ...
- 大话设计模式三之单一职责原则、开放-封闭原则、依赖倒置原则、里氏代换原则
单一职责原则 单一职责原则(SRP),意思就是说,功能要单一.准确解释是,就一个类而言,应该仅有一个引起它变化的原因. 如果一个类承担的职责过多,就等于把这些职责耦合在一起,一个职责的变化可能会削弱或 ...
- Java设计模式之设计的6大原则(开闭原则,里氏代换原则,依赖倒转原则,接口隔离原则,最少知道原则,合成复用原则)
1. 开闭原则 核心思想:一个对象对外扩展开发,对修改关闭 意思就是:对类的改动是通过增加代码进行的,而不是修改现有的代码. 也就是说软件开发人员一旦写出了可以运行的代码,就不应该去改动它,而是要保证 ...
- 【设计模式系列学习笔记】5、依赖倒转原则和里氏代换原则
依赖倒转原则:抽象不应该依赖细节,细节应该依赖于抽象: 针对接口编程,不要对实现编程: 高层模块不应该依赖底层模块,两个都应该依赖抽象: 抽象不应该依赖细节,细节应该依赖抽象: 里氏代换原则 一个软件 ...
- 系统设计原则之里氏代换原则
之前讲述的"开-闭"原则是系统设计的主原则,做到这点是一件很不容易的工作.但是也不是高不可攀的,除此原则以外还有其他的一些设计原则为实现或者说尽可能的达到"开-闭&quo ...
- 面向对象设计原则之里氏代换原则
里氏代换原则由2008年图灵奖得主.美国第一位计算机科学女博士Barbara Liskov教授和卡内基·梅隆大学Jeannette Wing教授于1994年提出.其严格表述如下:如果对每一个类型为S的 ...
最新文章
- JavaScript小记
- 是男人就下100层【第一层】——高仿微信界面(4)
- selenium+python自动化测试系列(一):登录
- 实现软件自动启动代码
- lisp 焊接符号标注_焊接符号标注大全
- python实现键盘记录器
- 【Java语法】DateFormat时间格式转化、java.util.Date和java.sql.Date之间的相互转化
- oracle按时间点还原数据
- ultra edit ftp帐号管理导入导出方法
- CentOS远程监控
- 组合数学 —— 基本计数原理
- kafka数据可靠传输
- mapview | 如何快速使用交互式地图展示空间数据信息
- 优秀的模糊测试代码是如何炼成的?
- 大数据平台层级架构图
- POJ 1053 Set Me G++
- 集成稳压电源的分类及特性
- java算法2——费氏数列
- 最佳Android模拟器,你值得拥有
- 100个常用的 PHP 类库、资源和技巧小结
热门文章
- wxWidgets:键码KeyCodes
- boost::mpl模块实现upper_bound相关的测试程序
- boost::mpl模块实现has_xxx相关的测试程序
- boost::make_maximal_planar用法的测试程序
- Boost::Flyweight 基本示例
- Boost::context模块fiber的解析器测试程序
- VTK:图片之Transparency
- VTK:图片之ImageGradientMagnitude
- VTK:Filtering之Delaunay2D
- OpenCV SURF FLANN匹配的实例(附完整代码)