Tutorialsteacher

关注我们

文章
  • C#
  • C# 面向对象编程
  • ASP.NET Core
  • ASP.NET MVC
  • LINQ
  • 控制反转 (IoC)
  • Web API
  • JavaScript
  • TypeScript
  • jQuery
  • Angular 11
  • Node.js
  • D3.js
  • Sass
  • Python
  • Go lang
  • HTTPS (SSL)
  • 正则表达式
  • SQL
  • SQL Server
  • PostgreSQL
  • MongoDB
  • C# - 入门
  • C# - 版本历史
  • C# - 第一个程序
  • C# - 关键词
  • C# - 类和对象
  • C# - 命名空间
  • C# - 变量
  • C# - 隐式类型变量
  • C# - 数据类型
  • 数字
  • 字符串
  • DateTime
  • 结构体
  • 枚举
  • StringBuilder
  • 匿名类型
  • 动态类型
  • 可空类型
  • C# - 值类型和引用类型
  • C# - 接口
  • C# - 运算符
  • C# - if else 语句
  • C# - 三元运算符 ?
  • C# - Switch 语句
  • C# - For 循环
  • C# - While 循环
  • C# - Do-while 循环
  • C# - 分部类
  • C# - Static 关键字
  • C# - 数组
  • 多维数组
  • 交错数组
  • C# - 索引器
  • C# - 泛型
  • 泛型约束
  • C# - 集合
  • ArrayList
  • List
  • SortedList
  • Dictionary
  • Hashtable
  • Stack
  • Queue
  • C# - 元组 (Tuple)
  • C# - 值元组 (ValueTuple)
  • C# - 内置异常
  • 异常处理
  • throw 关键字
  • 自定义异常
  • C# - 委托
  • Func 委托
  • Action 委托
  • Predicate 委托
  • 匿名方法
  • C# - 事件
  • C# - 协变
  • C# - 扩展方法
  • C# - 流 I/O
  • C# - File 类
  • C# - FileInfo 类
  • C# - 对象初始化器
  • OOP - 概述
  • 面向对象编程
  • 抽象
  • 封装
  • 关联与组合
  • 继承
  • 多态
  • 方法重写
  • 方法隐藏
  • C# - SOLID 原则
  • 单一职责原则
  • 开闭原则
  • 里氏替换原则
  • 接口隔离原则
  • 依赖倒置原则
  • 设计模式
  • 单例模式
  • 抽象工厂模式
  • 工厂方法模式
Entity Framework Extensions - 提升 EF Core 9
  批量插入
  批量删除
  批量更新
  批量合并

SOLID:里氏替换原则 (Liskov Substitution Principle)

里氏替换原则 (Liskov Substitution Principle) 由 Barbara Liskov 于 1987 年提出。她用数学术语描述了该原则,如下所示:

令 φ(x) 为关于类型 T 的对象 x 的一个可证明属性。那么对于类型 S 的对象 y,其中 S 是 T 的子类型,φ(y) 也应该为真。

LSP 指导如何在面向对象编程中使用继承。它关于子类型,以及如何从基类型正确派生一个类型。Robert Martin 解释 LSP 如下:

子类型必须能够替换其基类型。

在这里,类型可以是 C# 中的接口、类或抽象类。

让我们进一步简化它。派生类必须能够正确替换其基类。当您从基类派生一个类时,派生类应该正确实现基类的所有方法。它不应该通过抛出 NotImplementedException 来移除某些方法。

考虑以下 IMyCollection 接口,它可以用于创建任何类型的集合类。

public interface IMyCollection
{ 
    void Add(int item);
    void Remove(int item);
    int Get(int idex);
}

public class MyReadOnlyCollection : IMyCollection
{
    private IList<int> _collection;

    public MyReadOnlyCollection(IList&lt;int&gt; col)
    {
        _collection = col;
    }
    public void Add(int item)
    {
        throw new NotImplementedException();
    }

    public int Get(int index)
    {
        return _collection[index];
    }

    public void Remove(int item)
    {
        throw new NotImplementedException();
    }
}

上述示例违反了里氏替换原则,因为 MyReadOnlyCollection 类实现了 IMyCollection 接口,但它对 Add() 和 Remove() 方法抛出 NotImplementedException,因为 MyReadOnlyCollection 类是只读集合,所以不能添加或移除任何项。LSP 建议子类型必须能够替换基类或基接口。在上述示例中,我们应该为只读集合创建另一个不包含 Add() 和 Remove() 方法的接口。

让我们理解“派生类应该正确实现基类方法”的含义。

考虑以下 Rectangle 类

public class Rectangle {
    public virtual int Height { get; set; }
    public virtual int Width { get; set; }
}

从数学上讲,正方形与四边相等的矩形相同。我们可以在这里使用继承的“is-a”关系。正方形是矩形。Square 类可以继承 Rectangle 类,并使其高度和宽度相等,如下所示。

class Square : Rectangle
{
    private int _height;
    private int _width;

    public override int Height
    {
        get { return _height; }
        set { 
            _height = value; 
            _width = value;    
        }
    }

    public override int Width
    {
        get { return _width; }
        set
        {
            _width = value;
            _height = value;
        }
    }
}

以下计算矩形面积

public class AreaCalculator
{
    public static int CalculateArea(Rectangle r)
    { 
        return r.Height * r.Width;    
    }
}

现在,以下返回错误的结果

示例:LSP 违规
Rectangle sqr1 = new Square();
sqr1.Height = 6;
sqr1.Width = 8;
		
Console.WriteLine(AreaCalculator.CalculateArea(sqr1)); //returns 64
		
Rectangle sqr2 = new Square();
sqr2.Height = 8;
sqr2.Width = 6;
		
Console.WriteLine(AreaCalculator.CalculateArea(sqr2)); //returns 36
尝试一下

LSP 指出派生类应正确实现基类方法。在这里,正方形类不是矩形类的子类型,因为它具有相等的边。因此,只需要一个属性而不是两个属性(高度和宽度)。这会给类的用户带来困惑,并可能给出错误的结果。

TUTORIALSTEACHER.COM

TutorialsTeacher.com 是您权威的技术教程来源,旨在通过循序渐进的方法,指导您掌握各种网络和其他技术。

我们的内容旨在帮助所有水平的学习者轻松快速地掌握技术。访问此平台即表示您已阅读并同意遵守我们的使用条款和隐私政策,这些条款和政策旨在保护您的体验和隐私权利。

[email protected]

关于我们使用条款隐私政策
copywrite-symbol

2024 TutorialsTeacher.com. (v 1.2) 版权所有。