里氏替换原则

一 里氏替换原则(Liskov Substitution Principle, LSP)

要么别继承,如果继承,就要支持父类所有方法


一句话核心思想

"子类可以替换父类,并且程序不会出错。"

(就像你爸的手机你能用,你的手机你爸也能用,谁用都不会出问题!)


通俗解释(现实例子)

假设你有一个 "鸟" 类,它有个方法 "飞":

java 复制代码
class Bird {
    void fly() {
        System.out.println("鸟儿飞翔~");
    }
}

然后你写了个 "企鹅" 类继承 "鸟":

java 复制代码
class Penguin extends Bird {
    @Override
    void fly() {
        throw new RuntimeException("企鹅不会飞!"); // 违背LSP!
    }
}

问题来了:

  • 如果别人调用 Bird bird = new Penguin(); bird.fly(); → 程序崩溃!
  • 这就是违反LSP,因为 企鹅(子类)不能安全替换鸟(父类)。

正确做法(遵守LSP)

  1. 要么别继承 (企鹅本就不该继承"会飞的鸟"):

    java 复制代码
    class Bird { } // 普通鸟
    class FlyingBird extends Bird { void fly() { ... } } // 会飞的鸟
    class Penguin extends Bird { } // 企鹅不会飞,但不继承FlyingBird
  2. 要么子类别破坏父类行为 (如果继承,就要支持父类所有方法 ):

    java 复制代码
    class Penguin extends Bird {
        @Override
        void fly() {
            System.out.println("企鹅不会飞,但可以游泳!"); // 不报错,而是优雅处理
        }
    }

关键记忆点(LSP核心规则)

  1. 子类必须完全支持父类的功能(不能"阉割"父类方法)。
  2. 子类可以扩展功能,但不能改变父类的初衷(比如父类是"飞",子类不能改成"跑")。
  3. 调用父类的地方,换成子类也不会报错(这是黄金检验标准!)。

实际代码中如何遵守?

✅ 正确示范:

  • 父类 File 有 read() 方法,子类 PDFFile 和 TXTFile 都实现 read(),但内部逻辑不同。
  • 父类 List 有 add() 方法,子类 UnmodifiableList 直接禁止修改(抛出明确异常,而非隐藏错误)。

❌ 错误示范:

  • 父类 Rectangle 有 setWidth() 和 setHeight(),子类 Square 改成只用一个边长(违反数学逻辑)。
  • 父类 Database 有 connect(),子类 MockDatabase 的 connect() 直接返回 null(应返回模拟连接)。

一句话总结

"子类要像充话费送的亲儿子,不能像捡来的干儿子------该有的功能一个不能少,但可以更牛逼!"

二 为什么继承xxxFragment违反里氏替换原则(LSP):

  1. LSP核心原则:
  • 子类应该能够替换父类,而不改变程序的正确性
  • 子类可以扩展父类的功能,但不应该改变父类的功能
  1. xxxFragment包含特定的空调业务逻辑:
kotlin 复制代码
class xxxFragment : BasexxxFragment() {
    private val frontFragment by lazy { FxxFragment() }
    private val rearFragment by lazy { RxxFragment() }
    
    private fun setupFragments() {
        // 空调特有的前后排切换逻辑
        childFragmentManager.beginTransaction()
            .add(R.id.fragmentContainer, rearFragment)
            .hide(rearFragment)
            .add(R.id.fragmentContainer, frontFragment)
            .commit()
    }
}
  1. 违反LSP的情况:
  • 如果其他Fragment(如MassageFragment)继承AirConditionFragment
  • 它会继承到不需要的空调UI逻辑
  • 必须重写或忽略父类的空调相关方法
  • 这破坏了父类的行为预期

正确的做法是创建SharedViewModelFragment作为基类,因为:

  1. 只包含共享的ViewModel逻辑

  2. 不包含具体业务实现

  3. 子类可以安全扩展而不违反LSP

三 里氏替换原则的具体含义可以概括为以下几点

1‌.子类必须能够替换其基类‌:在任何基类可以出现的地方,子类都可以出现,并且不会改变程序的行为。

‌2.子类扩展而非修改‌:子类可以增加新的行为,但不能改变或删除父类已有的功能。这意味着子类可以添加新的方法或重载父类的方法,但不能重写父类的非抽象方法。

3‌. 对开闭原则的补充‌:里氏替换原则是对开闭原则(Open-Closed Principle)的补充,强调通过继承和抽象化来实现软件的可扩展性和可维护性。

参考:

https://blog.csdn.net/lilinhai548/article/details/141287849

相关推荐
Code Man12 分钟前
实现 Android 字符设备驱动
android·驱动开发·lineageos
传奇开心果编程21 分钟前
【Flutter入门练中学】第3课:滚动与列表
android·学习·flutter·ui·ios
JosieBook24 分钟前
【数据库】MySQL 实战精通系列 · 第4篇:索引原理与执行计划实战
android·数据库·mysql
mmsx31 分钟前
Android UI 复用体系:泛型基类、骨架与插槽
android·kotlin
Cici_ovo1 小时前
手机数据删除原理、运行内存、闪存、机械硬盘完整原理详解
android·智能手机
hi_LeTian1 小时前
【Linphone】Ubuntu20.04 编译 Linphone5.2 Android SDK 适配RK3326硬解码完整教程(避坑版)
android
SoStraw1 小时前
跨平台P2P通信SDK,Windows/Android/iOS/Linux/macOS一套API全兼容
android·linux·windows·跨平台·p2p·webrpc
李游Leo2 小时前
《HarmonyOS 7 ArkGraphics 3D 空间设计开发实战》07:复杂3D场景的帧率、内存与资源性能优化【鸿蒙心迹】
android·3d·性能优化·harmonyos
天神哥哥啊2 小时前
unity联调注意事项-安卓
android·unity·游戏引擎
机核研创社2 小时前
polo 长袖短裤套装自动化产线:八台机器排队接力
android·java·自动化