Objective-C中里氏替换原则

里氏替换原则是面向对象设计的基本原则之一,它指出子类对象可以在任何需要父类对象的地方使用,而不会产生意外的行为。

// 父类
@interface Animal : NSObject
- (void)sayHello;
@end@implementation Animal
- (void)sayHello {NSLog(@"Animal says hello");
}
@end// 子类1
@interface Dog : Animal
@end@implementation Dog
- (void)sayHello {NSLog(@"Dog says hello");
}
@end// 子类2
@interface Cat : Animal
@end@implementation Cat
- (void)sayHello {NSLog(@"Cat says hello");
}
@end// 使用场景
void greetAnimal(Animal *animal) {[animal sayHello];
}int main() {Animal *animal1 = [[Animal alloc] init];Animal *animal2 = [[Dog alloc] init];Animal *animal3 = [[Cat alloc] init];greetAnimal(animal1); // 输出:Animal says hellogreetAnimal(animal2); // 输出:Dog says hellogreetAnimal(animal3); // 输出:Cat says helloreturn 0;
}

在上面的代码中,定义了一个父类`Animal`和两个子类`Dog`和`Cat`,它们都继承自`Animal`。在`main`函数中,我们创建了一个`Animal`的实例`animal1`,以及`Dog`和`Cat`的实例`animal2`和`animal3`。然后,我们通过`greetAnimal`函数向这些对象发送`sayHello`消息,根据多态的特性,每个对象调用自己相应的方法。

根据里氏替换原则,我们可以将`Dog`和`Cat`的实例赋值给`Animal`类型的变量,在使用`greetAnimal`函数时,这些子类对象能够正常地替换父类对象,展示了里氏替换的灵活性。

在应用里氏替换原则时,需要注意以下几个方面:

1. 子类必须完全实现父类的接口:子类在继承父类时,要确保完全实现了父类的接口。即子类的方法参数、返回值类型要与父类一致,而且需遵循相同的约定和含义。否则,在使用父类对象的地方替换为子类对象时,可能会导致类型转换错误或意外的行为。

2. 子类不得强制修改父类的方法的意义:子类可以通过重写父类方法来改变方法的具体实现,但是不能修改方法的输入输出、语义和约束条件。如果子类修改了父类方法的含义,将会违背里氏替换原则,并可能导致依赖父类的代码出现错误。

3. 子类的前置条件(输入)不能强于父类:子类在重写父类方法时,不能抛出更多或更严格的异常,不能设置比父类更严格的前置条件(方法参数限制)。因为父类的方法被调用者所依赖,如果子类强化了条件,可能会导致调用者无法正常使用。

4. 子类的后置条件(输出)不能弱于父类:子类在重写父类方法时,不能返回比父类更少的结果,也不能抛出比父类更少的异常。因为调用父类方法的代码可能依赖于父类方法的返回结果和异常处理。

5. 尽量使用抽象类或接口作为父类:在应用里氏替换原则时,最好使用抽象类或接口作为父类,而不是具体的实现类。这样能够约束子类实现必要的方法,并且遵循里氏替换原则更加严格。

里氏替换原则的作用主要体现在以下几个方面:

1. 提高代码的可复用性:里氏替换原则使得子类对象能够替换父类对象,从而增加了代码的灵活性和可复用性。通过定义抽象的父类,可以在不改变原有代码的基础上,用不同的子类对象来实现不同的行为。

2. 提高代码的可扩展性:通过遵循里氏替换原则,新增一个子类或扩展子类的功能将不会对原有的代码产生影响,可以在不修改原有代码的情况下增加新的功能。

3. 提高代码的可维护性:里氏替换原则减少了类之间的依赖关系,降低了代码的耦合性,有利于代码的维护和修改,当需要修改某个功能时,只需关注相应的子类即可。

4. 促进多态的使用:里氏替换原则是实现多态性的重要手段之一。通过多态性,程序可以更加灵活地处理不同类型的对象,屏蔽了具体类型的差异,使得代码更加可读和可扩展。

综上所述,里氏替换原则在面向对象设计中扮演着重要的角色,能够提高代码的可复用性、可扩展性、可维护性,并促进多态的使用。通过合理地应用里氏替换原则,可以使程序设计更加灵活、可靠、易于拓展。

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

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

相关文章

一篇文章了解系统眼中的键盘--以一个简单的系统分析从按键的输入到字符的显示

键盘输入 实现使用的设备 intel架构32位CPU, 思路为嵌入式系统工程师,使用的操作系统是《30天自制操作系统》里面的系统进行讲解 硬件实现 按键 使用单片机等的引脚可以获取电平状态从而获得按键的状态(单片机是一种集成到一块硅片上构成的一个小而完善的微型计算机系统, 用…

每日OJ题_算法_模拟②_力扣495. 提莫攻击

目录 力扣495. 提莫攻击 解析代码 力扣495. 提莫攻击 495. 提莫攻击 难度 简单 在《英雄联盟》的世界中,有一个叫 “提莫” 的英雄。他的攻击可以让敌方英雄艾希(编者注:寒冰射手)进入中毒状态。 当提莫攻击艾希&#xff0c…

分享一个WPF项目

最近在学习WPF开发方式,找到一些项目进行拆解学习;本位主要分享一个WPF项目,叫做WPFDevelopers,在git上大约有1.3K星,话不多说,先看看效果: 这个项目开发可以编译启动后直接查看样例、Xaml、Cha…

LeetCode:LCP 24. 数字游戏(对顶堆求中位数 Java)

目录 LCP 24. 数字游戏 题目描述: 实现代码与解析: 原理思路: LCP 24. 数字游戏 题目描述: 小扣在秋日市集入口处发现了一个数字游戏。主办方共有 N 个计数器,计数器编号为 0 ~ N-1。每个计数器上分别显示了一个数…

《计算机网络简易速速上手小册》第9章:物联网(IoT)与网络技术(2024 最新版)

文章目录 9.1 IoT 架构与通信协议 - 打造智能世界的秘诀9.1.1 基础知识9.1.2 重点案例:使用 Python 和 MQTT 实现智能家居照明系统准备工作Python 脚本示例发布者(灯光控制)订阅者(灯光状态接收): 9.1.3 拓…

快速Diff算法-Vue3

快速Diff算法 快速 Diff 算法在实测中性能最优。它借鉴了文本 Diff 算法中的预处理思路,先处理新旧两组子节点中相同的前置节点和相同的后置节点。当前置节点和后置节点全部处理完毕后,如果无法简单地通过挂载新节点或者卸载已经不存在的节点来完成更新…

AD24-Class、飞线、PCB Nets的管理及添加、层的管理

一、Class 1、Class介绍 2、Class添加与显示 ①添加 ②显示通过Panels-PCB,即可将创建的类显示再左上方窗口 3、Class的编辑管理 ①概述 ②颜色更改 二、飞线 1、概述 2、 飞线的打开、关闭 打开:Alt左上角滑动 N:可以针对性的显示和隐…

Linux:使用grep和more索日志内容排查Bug

grep # 搜索文件内容显示行号 grep -n "要搜索的关键词" 文件名more 快捷键: 空白键(space)下一页b键 (back)上一页 示例 # 从第 20 行开始显示文档内容 more 20 文件名参考 linux查看命令 more 、les…

深度学习环境配置:Anaconda 安装和 pip 源

conda是一种通用包管理系统,与pip的使用类似,环境管理则允许用户方便地安装不同版本的python并可以快速切换。 Anaconda则是一个打包的集合,里面预装好了conda、某个版本的python、众多packages、科学计算工具等等,就是把很多常用…

Vue3 - 从 vue2 到 vue3 过渡,这一套就够了(案例 + 效果演示)(二)

目录 一、组合式 API 的使用 1.1、watch 函数 1.2、watchEffect 函数 1.3、toRef 和 toRefs 1.3.1、toRef 1.3.2、toRefs 1.4、vue3 的声明周期 一、组合式 API 的使用 1.1、watch 函数 与 vue2.x 中的 watch 配置功能一致,但是多了一些坑: 这…

Attempt to invoke virtual method ‘-‘ on a null object reference错误总结

Android studio开发 出现这个问题一般是:一个Activity中调用另一个xml布局文件,即非本Activity所绑定的xml布局文件中的控件,这时候就不能直接findViewById,不然会报错指向空对象 LayoutInflater factory LayoutInflater.from(…

【蓝桥杯】环形链表的约瑟夫问题

目录 题目描述: 输入描述: 输出描述: 示例1 解法一(C): 解法二(Cpp): 正文开始: 题目描述: 据说著名犹太历史学家 Josephus 有过以下故事&a…

Pytest测试用例参数化

pytest.mark.parametrize(参数名1,参数名2...参数n, [(参数名1_data1,参数名2_data1...参数名n_data1),(参数名1_data2,参数名2_data2...参数名n_data2)]) 场景: 定义一个登录函数test_login,传入参数为name,password,需要用多个账号去测试登录功能 # …

[职场] 留学生课程辅导待遇 #媒体#经验分享#其他

留学生课程辅导待遇 留学生课程辅导师需要具备专业知识和良好的沟通技巧,能够全面帮助留学生解决学习和生活方面的问题,提高留学生的学习效果和适应能力。 工作内容: 1.提供学习计划和课程指导:留学生课程辅导师可以帮助留学生…

JAVA方法引用:

方法引用的出现原因在使用Lambda表达式的时候,我们实际上传递进去的代码就是一种解决方案:拿参数做操作那么考虑一种情况:如果我们在Lambda中所指定的操作方案,已经有地方存在相同方案,那是否还有必要再写重复逻辑呢&a…

Go中的并发性介绍

并发是一个很酷的话题,一旦你掌握了它,就会成为一笔巨大的财富。说实话,我一开始很害怕写这篇文章,因为我自己直到最近才对并发性不太适应。我已经掌握了基础知识,所以我想帮助其他初学者学习Go的并发性。这是众多并发…

Java SWT Composite 绘画

Java SWT Composite 绘画 1 Java SWT2 Java 图形框架 AWT、Swing、SWT、JavaFX2.1 Java AWT (Abstract Window Toolkit)2.2 Java Swing2.3 Java SWT (Standard Widget Toolkit)2.4 Java JavaFX 3 比较和总结 1 Java SWT Java SWT(Standard Widget Toolkit&#xff…

C++从零开始的打怪升级之路(day30)

这是关于一个普通双非本科大一学生的C的学习记录贴 在此前,我学了一点点C语言还有简单的数据结构,如果有小伙伴想和我一起学习的,可以私信我交流分享学习资料 那么开启正题 今天分享的是关于list的基本函数使用 list是一个双向带头循环的…

02 使用jdk运行第一个java程序:HelloWorld

使用jdk运行第一个java程序 1 HelloWorld小案例1.1 编写流程1.2 错误示例 首先在CMD命令行里面,使用javac xxxx.java, 进行编译,其中会有报错; 然后生成xxxx.class 文件,然后使用java xxxx.class 进行运行。 1 HelloWo…

瑞_23种设计模式_抽象工厂模式

文章目录 1 抽象工厂模式(Abstract Factory Pattern)1.1 概念1.2 介绍1.3 小结1.4 结构 2 案例一2.1 案例需求2.2 代码实现 3 案例二3.1 需求3.2 实现 4 总结4.1 抽象工厂模式优缺点4.2 抽象工厂模式使用场景4.3 抽象工厂模式VS工厂方法模式4.4 抽象工厂…