里氏替换原则经典反例:正方形不是长方形

里氏替换原则指出:“继承必须确保超类所拥有的性质在子类中仍然成立”,在程序中的表现就是某个接口能接受超类对象为参数,那么它也必须应该能接受子类对象为参数,且程序不会出现异常。也就是说子类对象应该能够替换掉超类对象,而程序的行为不会改变。

最经典的用于说明里氏替换原则的反例就是“正方形不是长方形”。

假设我们有一个 Rectangle 类,它有 width 和 height 两个属性,以及它们的 getter 和 setter 方法,还有一个 area 方法用于求矩形的面积。

class Rectangle {
public:virtual void setWidth(int w) {width = w;}virtual void setHeight(int h) {height = h;}int getWidth() const {return width;}int getHeight() const {return height;}virtual int area() const {return width * height;}
protected:int width;int height;
};

这里的 width、height 需要设置为 protected,否则继承后将无法访问这两个属性。

然后我们创建一个 Square 类,它继承了 Rectangle 类,因为它们的长和高总是相等的,所以我们要重写 width 和 height 的 setter方法。

class Square : public Rectangle {
public:void setWidth(int w) override {width = height = w;}void setHeight(int h) override {width = height = h;}
};

然后现在有个接口,它接受 Rectangle 对象的引用作为参数,并设置长和宽,然后调用 area 并设置断言判断与预期是否一致。

void process(Rectangle& r) {r.setWidth(5);r.setHeight(4);assert(r.area() == 20); // 当 r 为 Square 时断言错误。
}

这里的断言在 r 为 Rectangle 时会成功,而 r 为 Square 时会失败。

int main() {Rectangle r;process(r); // 成功Square s;process(s); // 失败return 0;
}

很明显,在接口 process 中 Square 不能替换 Rectangle,因为当 Square 替换 Rectangle 作为参数时,程序发生了异常,出现了预期之外的结果。而最根本的原因是 Square 不能继承 Rectangle 中,因为 Rectangle 的属性 width 和 height 并不全是 Square 应该拥有的属性,或者说 Square 不应该拥有两个独立的属性,而应该拥有单一的边长属性 side。

所以,为了确保里氏替换原则成立,我们应该取消 Square 对 Rectangle的继承,重新给 Square 和 Rectangle 设计一个更高层的抽象,如 Shape,Shape 中有一个 Square 和 Rectangle 共有的属性 area,然后让 Square 和 Rectangle 都继承 Shape。

抽象类 Shape:

class Shape {
public:virtual int area() const = 0; 
};

Rectangle 继承 Shape 重写 area 接口并定义自己独特的成员变量 width 和 height 以及对应的 setter:

class Rectangle : public Shape {
public:void setWidth(int w) {width = w;}void setHeight(int h) {height = h;}int area() const override {return width * height;}
private:int width;int height;
};

Square 继承 Shape 重写 area 接口并定义自己独特的成员变量 side 以及对应的 setter:

class Square : public Shape {
public:void setSide(int s) {side = s;}int area() const override {return side * side;}
private:int side;
};

接口 process 接收超类 Shape 作为参数:

void process(Shape& s) {std::cout << "Area: " << s.area() << std::endl;
}

在 main 函数中 process 分别接受 Rectangle 和 Square 类型对象:

int main() {Rectangle r;r.setWidth(5);r.setHeight(4);process(r); // 成功Square s;s.setSide(5);process(s); // 成功return 0;
}

运行程序后发现,无论是 Rectangle 还是 Square 类型对象 process 接口均能正常处理并且没有出现异常,也就意味着 Rectangle 和 Square 两个子类能替换掉超类并且程序行为没有改变,也就说明这次的继承关系和接口设计符合里氏替换原则。

以上就是本文的全部内容,需要完整可运行代码请查看 Github 仓库GnCDesignPatterns

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/846515.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

力扣136.只出现一次的数字

给你一个 非空 整数数组 nums &#xff0c;除了某个元素只出现一次以外&#xff0c;其余每个元素均出现两次。找出那个只出现了一次的元素。你必须设计并实现线性时间复杂度的算法来解决此问题&#xff0c;且该算法只使用常量额外空间。 示例 1 &#xff1a;输入&#xff1a;n…

探讨大米自动化生产线包装设备的智能化发展趋势

随着科技的飞速发展&#xff0c;智能化已经成为各行各业转型升级的重要方向。在大米生产领域&#xff0c;自动化生产线包装设备的智能化发展更是引领着粮食产业的未来潮流。星派将从智能化技术、市场需求、发展趋势等方面&#xff0c;探讨大米自动化生产线包装设备的智能化发展…

从0开发一个Chrome插件:创建第一个Chrome插件

前言 这是《从0开发一个Chrome插件》系列的第四篇文章,本系列教你如何从0去开发一个Chrome插件,每篇文章都会好好打磨,写清楚我在开发过程遇到的问题,还有开发经验和技巧。 专栏: 从0开发一个Chrome插件:什么是Chrome插件? 从0开发一个Chrome插件:开发Chrome插件的必…

LeetCode 算法:找到字符串中所有字母异位词c++

原题链接&#x1f517;&#xff1a;找到字符串中所有字母异位词 难度&#xff1a;中等⭐️⭐️ 题目 给定两个字符串 s 和 p&#xff0c;找到 s 中所有 p 的 异位词 的子串&#xff0c;返回这些子串的起始索引。不考虑答案输出的顺序。 异位词 指由相同字母重排列形成的字符…

Python高阶学习记录

文章导读 阅读本文需要一定的python基础&#xff0c;部分知识点是对python入门篇学习记录和python并发编程学习记录的深入探究&#xff0c;本文记录的Python知识点包括函数式编程&#xff0c;装饰器&#xff0c;生成器&#xff0c;迭代器&#xff0c;正则表达式&#xff0c;内存…

eNSP——两台电脑通过一根网线直连通信

一、拓扑结构 二、电脑配置 ip和子网掩码&#xff0c;配置两台电脑处于同一网段 三、测试 四、应用 传文件等操作&#xff0c;可以在一台电脑上配置FTP服务器

Java零基础-顺序结构

哈喽&#xff0c;各位小伙伴们&#xff0c;你们好呀&#xff0c;我是喵手。运营社区&#xff1a;C站/掘金/腾讯云&#xff1b;欢迎大家常来逛逛 今天我要给大家分享一些自己日常学习到的一些知识点&#xff0c;并以文字的形式跟大家一起交流&#xff0c;互相学习&#xff0c;一…

高清矩阵是什么?

在数学中&#xff0c;矩阵是一个按照长方阵列排列的复数或实数集合&#xff0c;最早来自于方程组的系数及常数所构成的方阵。如图为m行n列的矩阵&#xff1a; 由此延伸可以想到矩阵图片是把一个三维空间分切成多个行和列的区域进行图像捕获&#xff0c;将捕获图像再进行拼合成为…

关于苹果发布IOS18系统,以及Siri升级贾维斯

随着科技的不断进步&#xff0c;手机操作系统也在持续升级&#xff0c;为用户提供更加智能化、便捷化的体验。近期&#xff0c;苹果公司即将推出的iOS 18系统引起了广泛关注。作为iPhone历史上的重大更新&#xff0c;iOS 18系统带来了众多新功能&#xff0c;将进一步提升iPhone…

2024-6-2 石群电路-21

2024-6-2&#xff0c;星期日&#xff0c;天气&#xff1a;阴&#xff0c;心情&#xff1a;晴。今天没什么特别的事情发生&#xff0c;心情还是一如既往的好&#xff0c;明天就周一啦&#xff0c;虽然我暂时不用上班&#xff0c;但是希望大家新的一周元气满满~ 今日观看了石群老…

STL中vector动态二维数组理解(杨辉三角)

题目链接&#xff1a;118.杨辉三角 题目描述&#xff1a; 给定一个非负整数 numRows&#xff0c;生成「杨辉三角」的前 numRows 行。 在「杨辉三角」中&#xff0c;每个数是它左上方和右上方的数的和。 题目指要&#xff1a; 本题的主要目的是理解vector<vector<int&…

18 跨团队 没有汇报线的人和事就是推不动?

在“05 | 大项目&#xff1a;把握关键点&#xff0c;谋定而后动”和“11 | 勤沟通&#xff1a;在信任的基础上&#xff0c;让沟通简单”两讲中&#xff0c;我提过“跨团队”这件事&#xff0c;很多同学带团队之后&#xff0c;无法回避的一个问题就是“跨团队协作”&#xff0c;…

【Linux】System V 消息队列(不重要)

一、消息队列的原理 一个进程给另一个进程发送类型数据块的方式每一个数据快都被认为是有一个类型的&#xff0c;接收者进程接收的数据快可以有不同的类型值 二、消息队列的接口 和共享内存的接口很像&#xff1a; 消息队列的创建 创建消息队列我们需要用msgget函数&#x…

logging二次封装

import logging import os import time from logging.handlers import RotatingFileHandlerclass Logger():logs_dir os.path.dirname(os.path.dirname(os.path.abspath(__file__))) \\report\\logsdef __init__(self, name):self.logger logging.getLogger(name)#设置级别…

JavaScript函数进阶学习

文章目录 JavaScript函数进阶函数提升作用流程 函数参数动态参数剩余参数展开运算符 箭头函数基本语法箭头函数参数箭头函数的this 遍历数组的forEach方法语法 JavaScript函数进阶 函数提升 函数有时可以先调用再声明。 作用流程 函数提升的作用流程与变量提升类似&#xf…

移动端框架:加速移动应用开发与提升跨平台兼容性

在当今快速发展的移动应用领域&#xff0c;开发者们面临着如何快速构建、维护并发布跨平台应用的挑战。为了应对这一挑战&#xff0c;移动端框架应运而生&#xff0c;它们不仅加速了移动应用的开发流程&#xff0c;还提升了应用的跨平台兼容性&#xff0c;并确保了应用性能与原…

C++的算法:动态规划算法

动态规划(Dynamic Programming,简称DP)是一种在数学、计算机科学和经济学中使用的,通过把原问题分解为相对简单的子问题的方式来求解复杂问题的方法。动态规划常常适用于有重叠子问题和最优子结构性质的问题。 动态规划的基本步骤: 1. 描述问题的最优解的结构:确定问题的…

2024/6/2 英语每日一段

However, they denied Hirst had been deliberately misleading, arguing that it was his “usual practice” to date physical works in a conceptual art project with the date of the project’s conception, which in the case of The Currency was 2016. Hirst and Sci…

Python | 自动探索性数据分析(EDA)库SweetViz

SweetViz是一个开放源代码Python库&#xff0c;主要用于生成精美的高密度可视化文件&#xff0c;启动探索性数据分析&#xff08;EDA&#xff09;&#xff0c;输出为完全独立的HTML应用程序。 探索性数据分析&#xff08;EDA&#xff09;是分析和总结数据集主要特征的过程&…

uni-app(优医咨询)项目实战 - 第7天

学习目标&#xff1a; 能够基于 WebSocket 完成问诊全流程 能够使用 uniCloud 云存储上传文件 能够完成查看电子处方的功能 能够完成医生评价的功能 一、问诊室 以对话聊天的方式向医生介绍病情并获取诊断方案&#xff0c;聊天的内容支持文字和图片两种形式。 首先新建一…