设计模式:里氏代换原则 - 继承设计的稳定之道

news2025/4/13 8:12:18

里氏代换原则(Liskov Substitution Principle, LSP)作为面向对象设计的基石之一,为我们提供了解决之道。它指导我们如何构建高扩展性和低维护成本的继承体系,避免代码行为不一致导致的混乱和错误。

一、错误的继承设计如何毁掉系统?

继承是面向对象设计的核心特性,但错误的继承设计会带来诸多问题:

• 子类篡改父类功能,导致父类逻辑异常;

• 接口不兼容,破坏多态性;

• 系统不稳定,甚至程序崩溃。

二、里氏代换原则-稳定代码的基石

里氏代换原则的核心思想是:子类必须能够替换掉他们的父类,并且保证系统行为不发生改变。

换句话说,继承关系中的子类必须完全遵守父类的契约,不能违背父类的行为预期。

这一原则表面上看似简单,但在实际开发中,常常被忽略甚至误解,导致代码可读性差、维护成本高、扩展性低。

案例分析

我们通过反例和正例来直观理解这一原则。

反例:不符合里氏代换原则的设计

场景:设计一个Bird类,让企鹅(Penguin)继承它。因企鹅不会飞,导致设计问题。

// 父类 Bird
public class Bird {
   //父类定义的通用行为:假设所有鸟类都能飞。 
    public void fly() {
        System.out.println("Flying...");
    }
}
// 子类 Penguin -继承Bird 类
public class Penguin extends Bird {
    /**
     * 重写父类的 fly 方法,但抛出了异常。
     */
    @Override
    public void fly() {
        throw new UnsupportedOperationException("Penguins can't fly!");
    }
}
// 测试代码
public class Main {
    public static void main(String[] args) {
        Bird bird = new Bird();
        bird.fly(); // 输出:Flying...

        Bird penguin = new Penguin();
        // 输出:抛出异常:UnsupportedOperationException: Penguins can't fly!
        penguin.fly();
    }
}

问题分析:

1.行为不一致

父类Bird假设所有鸟类都可以飞,但企鹅重写了fly方法并抛出异常,破坏了行为一致性。

2.违反多态性

调用者无法保证Bird类型变量的fly方法正常运行,破坏了多态的可靠性。

3.设计问题

将“飞行”强行定义在Bird类中,使得企鹅继承了不适合自身特性的功能。

正例:符合里氏代换原则的设计

为解决上述问题,重新设计父类 Bird。

// 抽象类 Bird
public abstract class Bird {
    /**
     * 定义鸟类的通用行为接口:移动方式
     * 子类需按自身特性实现移动方式(飞行、游泳等)。
     */
    public abstract void move();
}
// 会飞的鸟类 - FlyingBird
public class FlyingBird extends Bird {
    /**
     * 实现通用的移动行为:飞行
     * FlyingBird 表示所有能飞的鸟类。
     */
    @Override
    public void move() {
        System.out.println("Flying...");
    }
}
// 企鹅类 - Penguin
public class Penguin extends Bird {
    /**
     * 实现通用的移动行为:游泳
     * Penguin 表示不会飞的鸟类,但具备游泳能力。
     */
    @Override
    public void move() {
        System.out.println("Swimming...");
    }
}
// 测试代码
public class Main {
    public static void main(String[] args) {
        // 会飞的鸟类实例
        Bird sparrow = new FlyingBird();
        sparrow.move(); // 输出: Flying...

        // 企鹅类实例
        Bird penguin = new Penguin();
        penguin.move(); // 输出: Swimming...
    }
}

改进后的优势:

1.遵循里氏代换原则

子类FlyingBird和Penguin都实现了父类的move方法,行为符合父类预期。

2.提高扩展性

新增鸟类(如鸵鸟)时,只需实现其独特的move方法,无需修改现有代码。

3.设计更合理

将父类Bird的抽象行为设计为具有通用性的move()方法,避免了不会飞的鸟类继承不适合的行为。

4.减少错误风险

子类行为始终满足父类预期,避免运行时错误。

改进后的设计不仅符合里氏代换原则,还通过抽象和具体实现分离,优化了继承关系,也避免了行为冲突导致的多态失效。

三、里氏代换原则的价值

1.增强系统稳定性

遵循里氏代换原则可确保继承体系内子类和父类行为一致,避免因行为冲突导致的运行时异常。

2.提升代码扩展性

子类在不修改父类的情况下可实现新功能,符合开闭原则,让系统更加灵活。

四、适用场景

1.类继承设计

在构建继承体系时,确保子类不会破坏父类的行为逻辑。例如,在设计公共服务类时,子类应保持接口一致,避免行为冲突。

2.多态场景

多态的核心是“父类引用指向子类实例”,而里氏代换原则是多态实现的基础。例如,Shape类的子类(如Circle和Rectangle)必须遵守Shape的行为规范。

3.接口设计与模块交互

在模块化开发中,遵守里氏代换原则可确保模块间接口替换时不会影响系统功能。例如,微服务架构中的多实现服务需遵循接口规范。

五、总结

遵守里氏代换原则,不仅能避免继承体系中常见的设计陷阱,更能大幅提升代码的可扩展性和稳定性。

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

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

相关文章

特殊定制版,太给力了!

今天给大家分享一款超棒的免费录屏软件,真的是录屏的好帮手! 这款软件功能可以录制 MP4、AVI、WMV 格式的标清、高清、原画视频,满足你各种需求。 云豹录屏大师 多功能录屏神器 它的界面特别简洁,上手超快,用起来很顺…

go:实现最简单区块链

1.新建文件夹命名为blockchain,在此文件夹下分别创建两个文件一个为block.go另一个为chain.go如下图所示: 2.写入代码: block.go package blockchainimport ("bytes""crypto/sha256""encoding/gob""log""strconv""ti…

工业相机使用笔记

目前工业相机有多种分类方式,以下是基于不同原理和特点的类别总结: 按维度分类 2D相机: 原理:通过镜头将二维平面上的物体成像在图像传感器上,传感器上的像素点阵列捕捉物体的光信号,并转换为电信号或数字…

系分论文《论面向服务开发方法在设备租赁行业的应用》

系统分析师论文系列 【摘要】 2022年5月,我司承接某工程机械租赁企业"智能租赁运营管理平台"建设项目,我作为系统分析师主导系统架构设计。该项目需整合8大类2000余台设备资产,覆盖全国15个区域运营中心与300家代理商,实…

04--网络属性设置与多路复用

一、TCP可靠性分析 二、 scoket 属性设置 1、socket 属性设置表 NAMEgetsockopt, setsockopt - get and set options on sockets获取 和 设置 套接字属性 SYNOPSIS#include <sys/types.h> /* See NOTES */#include <sys/socket.h>int getsockopt(int so…

AI领域再突破,永洪科技荣获“2025人工智能+创新案例”奖

在2025年的今天&#xff0c;人工智能已从技术概念全面渗透至产业核心。中国作为全球AI技术应用的前沿阵地&#xff0c;正通过“人工智能”行动加速推进技术与实体经济深度融合。 这一背景下&#xff0c;永洪科技凭借其“国内某头部ICT人力资源板块GenAI项目”荣获“2025全国企业…

基于疾风大模型的新能源储能优化系统:方法、实现与案例分析

一、引言 随着可再生能源渗透率不断提高,储能系统在电力系统中的重要性日益凸显。传统储能控制方法主要基于规则策略和简单优化算法,难以应对高比例新能源场景下的复杂决策需求。本文将详细介绍如何利用疾风大模型(Gale Model)构建智能化的新能源储能优化系统,包含核心方…

菊风RTC 2.0 开发者文档正式发布,解锁音视频新体验!

重磅发布&#xff01; 开发者们&#xff0c;菊风实时音视频2.0文档已正式发布上线&#xff0c;为您提供更清晰、更高效的开发支持&#xff01;让菊风实时音视频2.0为您的音视频应用加速~ 菊风实时音视频2.0聚焦性能升级、体验升级、录制服务升级&#xff0c;助力视频通话、语…

OpenCv高阶(一)——图像金字塔(上采样、下采样)

目录 图像金字塔 一、上下采样原理 1、向下取样 2、向上采样 3、图像金字塔的作用 二、案例实现 1、高斯下采样 2、高斯金字塔中的上采样 3、对下采样的结果做上采样&#xff0c;图像变模糊&#xff0c;无法复原 4、拉普拉斯金字塔&#xff08;图片复原&#xff09; 图…

LEARNING DYNAMICS OF LLM FINETUNING【论文阅读笔记】

LEARNING DYNAMICS OF LLM FINETUNING 一句话总结 作者将LLM的学习动力机制拆解成AKG三项&#xff0c;并分别观察了SFT和DPO训练过程中​​正梯度信号​​和​​负梯度信号​​的变化及其带来的影响&#xff0c;并得到以下结论&#xff1a; ​​SFT通过梯度相似性间接提升无关…

数据集 | 沥青路面缺陷目标检测

文章目录 一、数据集概述1. 行业痛点与数据集价值2. 数据集技术规格 二、样本类别详解1. 裂缝 (Crack)2. 裂缝修补 (Crack Repair)3. 坑洞 (Pothole)4. 坑洞修补 (Pothole Repair)5. 井盖 (Manhole Cover)6. 其他 (Other) 三、标注工具四、下载地址 一、数据集概述 1. 行业痛点…

AllData数据中台升级发布 | 支持K8S数据平台2.0版本

&#x1f525;&#x1f525; AllData大数据产品是可定义数据中台&#xff0c;以数据平台为底座&#xff0c;以数据中台为桥梁&#xff0c;以机器学习平台为中层框架&#xff0c;以大模型应用为上游产品&#xff0c;提供全链路数字化解决方案。 ✨杭州奥零数据科技官网&#xf…

.net Core 和 .net freamwork 调用 deepseek api 使用流输出文本(对话补全)

.net Core 调用 deepseek api 使用流输出文本 简下面直接上代码&#xff08;.net core&#xff09;&#xff1a;最后再贴一个 .net Freamwork 4 可以用的代码TLS 的代码至关重要的&#xff1a;&#xff08;下面这个&#xff09; 简 在官网里面有许多的案例&#xff1a;我们通过…

springcloud整理

问题1.服务拆分后如何进行服务之间的调用 我们该如何跨服务调用&#xff0c;准确的说&#xff0c;如何在cart-service中获取item-service服务中的提供的商品数据呢&#xff1f; 解决办法&#xff1a;Spring给我们提供了一个RestTemplate的API&#xff0c;可以方便的实现Http请…

04-算法打卡-数组-二分查找-leetcode(69)-第四天

1 题目地址 69. x 的平方根 - 力扣&#xff08;LeetCode&#xff09;69. x 的平方根 - 给你一个非负整数 x &#xff0c;计算并返回 x 的 算术平方根 。由于返回类型是整数&#xff0c;结果只保留 整数部分 &#xff0c;小数部分将被 舍去 。注意&#xff1a;不允许使用任何内…

[Windows] 字体渲染 mactype v2025.4.11

[Windows] 字体渲染 mactype 链接&#xff1a;https://pan.xunlei.com/s/VONeCUP2hEgO5WIQImgtGUmrA1?pwdyruf# 025.4.11 Variable font support 可变字体支持已到来。 本版本将可变字体支持扩展到所有 GDI 应用程序。 所有 win32 程序中的字体&#xff0c;如 Noto Sans、Se…

VSCode CMake调试CPP程序

文章目录 1 安装C与CMake插件2 配置CMakeLists.txt3 使用CMake编译调试3.1 编译3.2 调试 4 自定义构建调试参考 1 安装C与CMake插件 C插件 CMake插件 2 配置CMakeLists.txt 编写测试程序 #include<iostream>int main(int argc, char const *argv[]) {int a 1, b 2;i…

Halo 设置 GitHub - OAuth2 认证指南

在当今数字化时代&#xff0c;用户认证的便捷性和安全性愈发重要。对于使用 Halo 搭建个人博客或网站的开发者而言&#xff0c;引入 GitHub - OAuth2 认证能够极大地提升用户登录体验。今天&#xff0c;我们就来详细探讨一下如何在 Halo 中设置 GitHub - OAuth2 认证。 一、为…

【unity游戏开发——Animator动画】Animator动画状态机复用——重写动画控制器 Animator Override Controller

注意&#xff1a;考虑到UGUI的内容比较多&#xff0c;我将UGUI的内容分开&#xff0c;并全部整合放在【unity游戏开发——Animator动画】专栏里&#xff0c;感兴趣的小伙伴可以前往逐一查看学习。 文章目录 一、状态机复用是什么&#xff1f;二、实战专栏推荐完结 一、状态机复…

C语言--汉诺塔问题

汉诺塔问题是一个典型的递归问题。 递归问题的基本思想&#xff1a;将问题逐步化简为相同思路但是规模更小的问题&#xff0c;直到问题可以直接解决 递归的关键在于基准情形和递归步骤&#xff0c;基准情形也就是退出条件&#xff0c;递归步骤也就是把问题简化为子问题的过程。…