软件工程设计原理里氏替换原则 ,具体实现及JAVA代码举例

简介: 里氏替换原则(Liskov Substitution Principle, LSP)是面向对象设计的基本原则之一,由Barbara Liskov提出。这个原则指出,如果类 S 是类 T 的子类型,则程序中使用 T 的对象的地方都可以不经修改地使用 S 的对象。换句话说,子类的对象应该能够替换掉它们的父类对象,而不影响程序的正确性。这个原则强调了继承关系中的行为兼容性,保证了基类和派生类之间的正确抽象和继承关系。

里氏替换原则(Liskov Substitution Principle, LSP)是面向对象设计的基本原则之一,由Barbara Liskov提出。这个原则指出,如果类 S 是类 T 的子类型,则程序中使用 T 的对象的地方都可以不经修改地使用 S 的对象。换句话说,子类的对象应该能够替换掉它们的父类对象,而不影响程序的正确性。这个原则强调了继承关系中的行为兼容性,保证了基类和派生类之间的正确抽象和继承关系。

具体实现

实现里氏替换原则的关键是确保子类的行为满足父类的行为契约。子类可以扩展父类的功能,但不应改变父类原有的功能。这通常意味着:

  • 子类不应重写父类的非抽象方法。
  • 子类的方法应保持与父类方法相同的输入参数类型和返回类型。
  • 子类的方法不应抛出父类方法未声明的异常。

举例前的分析:

  • 不遵守LSP:子类重写父类方法,改变了原有功能的行为。
  • 遵守LSP:子类扩展父类功能,保持原有功能的行为不变。

JAVA代码举例

假设有一个几何形状的类和两个子类:矩形和正方形。

不遵守里氏替换原则的代码:

java复制代码

class Rectangle {
    protected int width;
    protected int height;

    public void setWidth(int width) {
        this.width = width;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    public int getArea() {
        return width * height;
    }
}

class Square extends Rectangle {
    @Override
    public void setWidth(int width) {
        super.setWidth(width);
        super.setHeight(width);
    }

    @Override
    public void setHeight(int height) {
        super.setWidth(height);
        super.setHeight(height);
    }
}

在这个例子中,Square 类违反了里氏替换原则,因为它改变了 Rectangle 的行为,使得设置宽度或高度的操作同时改变了另一方。

遵守里氏替换原则的代码:

为了遵守LSP,应该重新设计类的结构,确保正方形和矩形之间的行为一致性。

java复制代码

interface Shape {
    int getArea();
}

class Rectangle implements Shape {
    private int width;
    private int height;

    public Rectangle(int width, int height) {
        this.width = width;
        this.height = height;
    }

    @Override
    public int getArea() {
        return width * height;
    }

    // Rectangle-specific methods
}

class Square implements Shape {
    private int sideLength;

    public Square(int sideLength) {
        this.sideLength = sideLength;
    }

    @Override
    public int getArea() {
        return sideLength * sideLength;
    }

    // Square-specific methods
}

在遵守LSP的代码中,通过引入一个共同的接口 ShapeRectangleSquare 都实现了这个接口,各自保留了它们独特的行为,同时满足了形状的基本契约。

实践中的好处

  • 增强程序的可读性和可维护性:保证了基类和子类之间的一致性,使得代码更易于理解和维护。
  • 提高代码的可重用性:遵循LSP的设计使得子类可以在不改变原有功能的前提下,用于父类可以使用的任何场合。
  • 促进模块间的松耦合:通过确保子类的替换不影响程序的正确性,可以更灵活地在不同模块间重用类。

遵循里氏替换原则有助于构建健壯且灵活的面向对象系统,确保了继承机制的正确使用和实现。

相关文章
|
8月前
|
Java 开发工具
【Azure Storage Account】Java Code访问Storage Account File Share的上传和下载代码示例
本文介绍如何使用Java通过azure-storage-file-share SDK实现Azure文件共享的上传下载。包含依赖引入、客户端创建及完整示例代码,助你快速集成Azure File Share功能。
566 6
|
8月前
|
Java 数据处理 API
为什么你的Java代码应该多用Stream?从循环到声明式的思维转变
为什么你的Java代码应该多用Stream?从循环到声明式的思维转变
384 115
|
8月前
|
安全 Java 编译器
为什么你的Java代码需要泛型?类型安全的艺术
为什么你的Java代码需要泛型?类型安全的艺术
278 98
|
8月前
|
Java 编译器 API
java最新版和java8的区别,用代码展示
java最新版和java8的区别,用代码展示
672 43
|
8月前
|
安全 Java 容器
告别空指针噩梦:Optional让Java代码更优雅
告别空指针噩梦:Optional让Java代码更优雅
532 94
|
8月前
|
安全 Java 容器
告别繁琐判空:Optional让你的Java代码更优雅
告别繁琐判空:Optional让你的Java代码更优雅
|
9月前
|
IDE Java 关系型数据库
Java 初学者学习路线(含代码示例)
本教程为Java初学者设计,涵盖基础语法、面向对象、集合、异常处理、文件操作、多线程、JDBC、Servlet及MyBatis等内容,每阶段配核心代码示例,强调动手实践,助你循序渐进掌握Java编程。
1157 3
|
8月前
|
JSON 网络协议 安全
【Java】(10)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
408 1
|
8月前
|
JSON 网络协议 安全
【Java基础】(1)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
382 1
|
9月前
|
数据采集 存储 弹性计算
高并发Java爬虫的瓶颈分析与动态线程优化方案
高并发Java爬虫的瓶颈分析与动态线程优化方案