AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / coding / 问题 / 79340103
Accepted
magva
magva
Asked: 2025-01-09 00:53:50 +0800 CST2025-01-09 00:53:50 +0800 CST 2025-01-09 00:53:50 +0800 CST

里氏替换原则如何与抽象类的具体实现中的类型特化一起工作?

  • 772

假设我们想模拟不同种类的食物:披萨和馅饼。披萨和馅饼都有一种配料,但它们的配料不同。

我们实现一个抽象类Baked,以及两个具体类Pizza和Pie。我们还实现一个抽象类Topping,以及两个具体类PizzaTopping和PieTopping。

根据定义, 的任何具体实现都Baked必须具有Topping,因此Baked应具有 类型的属性Topping。此外,此特定的 topping 属性应为PizzaTopping中的类型Pizza,并且PieTopping中的类型Pie。

如果我正确理解了前面的答案,那么在这种情况下 LSP 就会被违反,因为如果我们抛开抽象的事实Baked,就有可能实例化Baked持有 的 a ,但如果我们用PieTopping替换,这是不可能的。BakedPizza

我的问题是:有没有办法在不违反 LSP 的情况下实现这个模型?

oop
  • 2 2 个回答
  • 39 Views

2 个回答

  • Voted
  1. Best Answer
    Mark Seemann
    2025-01-09T03:15:20+08:002025-01-09T03:15:20+08:00

    我将首先解决当前的问题,然后我将谈谈该问题所隐含的总体假设。

    使用类似 C# 的伪代码,您可以Pizza像这样定义:

    public class Pizza : Baked
    {
        private readonly PizzaTopping topping;
    
        public Pizza(PizzaTopping topping) : this(topping)
        {
            // Consider saving `topping` to a private or protected class field
            // so that you don't have to downcast any `topping` field from the
            // base class:
            this.topping = topping;
        }
    }
    

    然后对整个班级做同样的事情Pie。

    这可能会引发一个自然的问题:为什么还要有一个抽象Topping类?

    确实,根据 OP 中的信息,我们没有足够的信息来回答这样的问题。是否Topping定义了派生类可以实现的一些多态行为?如果是,那是什么?这些是否与里氏替换原则 (LSP) 有关?

    不幸的是,大学、训练营和在线课程都坚持教授面向对象设计,认为它就是在现实世界中建模具体对象。这可能是Simula 的初衷,但很少被证明是 Java 或 C# 等语言中构建代码的最佳方式。

    LSP 不是关于结构,而是关于行为。维基百科条目实际上很好地概括了对 LSP 的现代理解,其中讨论了

    • 子类型中的先决条件无法得到加强
    • 后置条件在子类型中不能被削弱
    • 不变量在子类型中不能被削弱

    所有这些(先决条件、后置条件和不变量)在Bertrand Meyer 的 OOD 观点中都是类型契约的一部分。只有类型的设计者才能说出契约是什么,而且由于 OP 没有说明这一点,我们无法真正回答给定的设计是否违反了 LSP。

    • 1
  2. nik0x1
    2025-01-09T03:48:28+08:002025-01-09T03:48:28+08:00

    让我们尝试仔细分析一下您的问题。

    里氏替换原则(LSP):

    如果类 S 是类 T 的子类,则类 T 的对象应该可以被类 S 的对象替换,而不会改变程序的期望属性。

    在您的情况下,这意味着以下内容:如果您有一些代码(例如,方法f)作为Baked参数,那么如果您将实例Pizza或Pie作为参数传递给它,它应该可以正常工作。

    从这句话可以看出,如果不理解方法,以及类和中方法的实现,我们就无法谈论是否符合 LSP 。因为fBakedPizzaPie这些信息直接影响对“程序正确性”的理解。

    • 1

相关问题

  • 组合优于继承 - 代码重复

  • 是否有必要在具有流畅接口的方法中返回相同的对象

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    重新格式化数字,在固定位置插入分隔符

    • 6 个回答
  • Marko Smith

    为什么 C++20 概念会导致循环约束错误,而老式的 SFINAE 不会?

    • 2 个回答
  • Marko Smith

    VScode 自动卸载扩展的问题(Material 主题)

    • 2 个回答
  • Marko Smith

    Vue 3:创建时出错“预期标识符但发现‘导入’”[重复]

    • 1 个回答
  • Marko Smith

    具有指定基础类型但没有枚举器的“枚举类”的用途是什么?

    • 1 个回答
  • Marko Smith

    如何修复未手动导入的模块的 MODULE_NOT_FOUND 错误?

    • 6 个回答
  • Marko Smith

    `(表达式,左值) = 右值` 在 C 或 C++ 中是有效的赋值吗?为什么有些编译器会接受/拒绝它?

    • 3 个回答
  • Marko Smith

    在 C++ 中,一个不执行任何操作的空程序需要 204KB 的堆,但在 C 中则不需要

    • 1 个回答
  • Marko Smith

    PowerBI 目前与 BigQuery 不兼容:Simba 驱动程序与 Windows 更新有关

    • 2 个回答
  • Marko Smith

    AdMob:MobileAds.initialize() - 对于某些设备,“java.lang.Integer 无法转换为 java.lang.String”

    • 1 个回答
  • Martin Hope
    Fantastic Mr Fox msvc std::vector 实现中仅不接受可复制类型 2025-04-23 06:40:49 +0800 CST
  • Martin Hope
    Howard Hinnant 使用 chrono 查找下一个工作日 2025-04-21 08:30:25 +0800 CST
  • Martin Hope
    Fedor 构造函数的成员初始化程序可以包含另一个成员的初始化吗? 2025-04-15 01:01:44 +0800 CST
  • Martin Hope
    Petr Filipský 为什么 C++20 概念会导致循环约束错误,而老式的 SFINAE 不会? 2025-03-23 21:39:40 +0800 CST
  • Martin Hope
    Catskul C++20 是否进行了更改,允许从已知绑定数组“type(&)[N]”转换为未知绑定数组“type(&)[]”? 2025-03-04 06:57:53 +0800 CST
  • Martin Hope
    Stefan Pochmann 为什么 {2,3,10} 和 {x,3,10} (x=2) 的顺序不同? 2025-01-13 23:24:07 +0800 CST
  • Martin Hope
    Chad Feller 在 5.2 版中,bash 条件语句中的 [[ .. ]] 中的分号现在是可选的吗? 2024-10-21 05:50:33 +0800 CST
  • Martin Hope
    Wrench 为什么双破折号 (--) 会导致此 MariaDB 子句评估为 true? 2024-05-05 13:37:20 +0800 CST
  • Martin Hope
    Waket Zheng 为什么 `dict(id=1, **{'id': 2})` 有时会引发 `KeyError: 'id'` 而不是 TypeError? 2024-05-04 14:19:19 +0800 CST
  • Martin Hope
    user924 AdMob:MobileAds.initialize() - 对于某些设备,“java.lang.Integer 无法转换为 java.lang.String” 2024-03-20 03:12:31 +0800 CST

热门标签

python javascript c++ c# java typescript sql reactjs html

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve