搜索
首页Javajava教程在 Typescript 和 Java 中应用'里氏替换原则”

Aplicando o

概念

接口

接口定义类必须实现的契约或一组方法和属性。接口用于确保类遵循某种格式,但它们不提供方法的实现,仅提供方法的签名。

每当一个类实现一个接口时,它就会签署该接口的所有契约(方法和属性)。每个属性和方法都是强制实现的。

坚硬的

SOLID 是一个缩写词,代表面向对象编程的五个基本原则,由 Robert C. Martin(鲍勃大叔)提出。在这里您可以阅读有关他的文章的更多信息。
这些原则旨在改进代码的结构和维护,使其更加灵活、可扩展且更易于理解。这些原则可以帮助程序员创建更有组织的代码、划分职责、减少依赖、简化重构过程并促进代码重用。

关于LSP

缩写中的“L”代表“里氏替换原理”。 Bob叔叔用来定义这个原则的一句话是:

“派生类必须能够完全替换基类”

因此建议派生类应该尽可能接近基类,这样派生类就可以在代码不做任何修改的情况下替换其基类。

该原则由 Barbara Liskov 于 1988 年基于数据抽象和类型理论提出。源自契约式设计 (DBC) 的概念,由 Bertrand Meyer 于 1986 年推广。

这一原则的另一个具体说明是:

子类型应该用作您的基本类型,没有任何意外。

在编程中,变化和意外可能会导致问题。如果需要更换某项系统功能,新功能必须提供相同类型的信息,否则系统可能会出现故障。为了确保类 S 具有与基类 T 相同的行为,必须使用定义实现新功能的强制方法的契约(接口或抽象类),以保证类 S 之间相似性的完整性和 T 类。

实际应用

考虑一个带有 Fly() 方法的 Bird 基类,该方法将在两个子类中使用:Sparrow 和 Ostrich。

文件:bird.java

class Bird {
    void fly() {
        System.out.println("I can fly!");
    }
}

class Sparrow extends Bird {
    // Herda o comportamento de 'fly' da classe 'Bird'
}

class Ostrich extends Bird {
    @Override
    void fly() {
        throw new UnsupportedOperationException("I cannot fly");
    }
}

文件:bird.ts

class Bird {
  fly() {
    console.log("I can fly!");
  }
}

class Sparrow extends Bird {}

class Ostrich extends Bird {
  fly() {
    throw new Error("I cannot fly");
  }
}

遇到的问题

在这里,Sparrow 类遵循 LSP,因为麻雀确实可以飞。然而,Ostrich 类违反了 LSP,因为它重写了 voo() 方法,从根本上改变了其行为,打破了 Ave 类设定的期望。

如何修复?

我们需要通过将 Sparrow 和 Ostrich 类的每个特殊性划分为合约(接口或抽象类,这里我将使用接口)来应用 LSP,它们必须签署这些合约来调整每个类的行为:

文件:bird.java

interface Bird {
    String getName();
    void makeSound();
}

interface FlyingBird extends Bird {
    void fly();
}

class Sparrow implements FlyingBird {
    private String name;

    public Sparrow(String name) {
        this.name = name;
    }

    @Override
    public String getName() {
        return this.name;
    }

    @Override
    public void makeSound() {
        System.out.println("Chirp chirp!");
    }

    @Override
    public void fly() {
        System.out.println(this.name + " is flying!");
    }
}

class Ostrich implements Bird {
    private String name;

    public Ostrich(String name) {
        this.name = name;
    }

    @Override
    public String getName() {
        return this.name;
    }

    @Override
    public void makeSound() {
        System.out.println("Boom boom!");
    }
}

public class Main {
    public static void main(String[] args) {
        Sparrow sparrow = new Sparrow("Little Sparrow");
        sparrow.makeSound(); // Chirp chirp!
        sparrow.fly(); // Little Sparrow is flying!

        Ostrich ostrich = new Ostrich("Ostrich");
        ostrich.makeSound(); // Boom boom!
        ostrich.fly(); // Error: Method 'fly' does not exist on 'Ostrich'
    }
}

文件:bird.ts

interface Bird {
  name: string;
  makeSound(): void;
}

interface FlyingBird extends Bird {
  fly(): void;
}

class Sparrow implements FlyingBird {
  name: string;

  constructor(name: string) {
    this.name = name;
  }

  makeSound() {
    console.log("Chirp chirp!");
  }

  fly() {
    console.log(`${this.name} is flying!`);
  }
}

class Ostrich implements Bird {
  name: string;

  constructor(name: string) {
    this.name = name;
  }

  makeSound() {
    console.log("Boom boom!");
  }
}

const sparrow = new Sparrow("Little Sparrow");
sparrow.makeSound(); // Chirp chirp!
sparrow.fly(); // Little Sparrow is flying!

const ostrich = new Ostrich("Ostrich");
ostrich.makeSound(); // Boom boom!
ostrich.fly(); // Error: Method 'fly' does not exist on 'Ostrich'

分析

更正说明
Bird Interface:定义所有鸟类共有的行为,例如makeSound()。所有鸟类都必须实现此接口。

FlyingBird 接口:继承自 Ave 并添加 Fly() 行为,该行为特定于会飞的鸟类。

Sparrow 类:实现 FlyingBird 接口,因为麻雀可以飞。此类定义了发出声音和飞行的行为。

鸵鸟类:仅实现 Bird 接口,因为鸵鸟不会飞。该类没有 Fly() 方法,因此不违反 LSP。

结论

LSP 对于确保代码模块化、可重用且易于维护至关重要。违反 LSP 可能会导致脆弱的代码在引入新子类或修改现有子类时中断,因为这可能会导致依赖于超类的部分代码出现意外行为。

子类型替换允许模块无需修改即可扩展,这对于开闭原则 (OCP) 提供的灵活性至关重要,而里氏替换原则使之成为可能。契约(通过接口或抽象类实现)对于安全设计至关重要,但程序员必须充分理解它们,有助于避免遗留软件中的常见错误。他们还提供了有关如何实施和使用代码的宝贵指导,只需遵守相关合同即可。

实际意义

  1. 设计子类时,确保它们可以在使用其超类的任何地方使用,而不会引入错误或需要特殊处理。
  2. 避免创建违反超类预期行为的子类,因为这可能会导致维护问题和意外错误。

理解和应用里氏替换原则可以帮助开发人员创建更加可预测和稳定的面向对象系统。

以上是在 Typescript 和 Java 中应用'里氏替换原则”的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
如何将Maven或Gradle用于高级Java项目管理,构建自动化和依赖性解决方案?如何将Maven或Gradle用于高级Java项目管理,构建自动化和依赖性解决方案?Mar 17, 2025 pm 05:46 PM

本文讨论了使用Maven和Gradle进行Java项目管理,构建自动化和依赖性解决方案,以比较其方法和优化策略。

如何使用适当的版本控制和依赖项管理创建和使用自定义Java库(JAR文件)?如何使用适当的版本控制和依赖项管理创建和使用自定义Java库(JAR文件)?Mar 17, 2025 pm 05:45 PM

本文使用Maven和Gradle之类的工具讨论了具有适当的版本控制和依赖关系管理的自定义Java库(JAR文件)的创建和使用。

如何使用咖啡因或Guava Cache等库在Java应用程序中实现多层缓存?如何使用咖啡因或Guava Cache等库在Java应用程序中实现多层缓存?Mar 17, 2025 pm 05:44 PM

本文讨论了使用咖啡因和Guava缓存在Java中实施多层缓存以提高应用程序性能。它涵盖设置,集成和绩效优势,以及配置和驱逐政策管理最佳PRA

如何将JPA(Java持久性API)用于具有高级功能(例如缓存和懒惰加载)的对象相关映射?如何将JPA(Java持久性API)用于具有高级功能(例如缓存和懒惰加载)的对象相关映射?Mar 17, 2025 pm 05:43 PM

本文讨论了使用JPA进行对象相关映射,并具有高级功能,例如缓存和懒惰加载。它涵盖了设置,实体映射和优化性能的最佳实践,同时突出潜在的陷阱。[159个字符]

Java的类负载机制如何起作用,包括不同的类载荷及其委托模型?Java的类负载机制如何起作用,包括不同的类载荷及其委托模型?Mar 17, 2025 pm 05:35 PM

Java的类上载涉及使用带有引导,扩展程序和应用程序类负载器的分层系统加载,链接和初始化类。父代授权模型确保首先加载核心类别,从而影响自定义类LOA

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
1 个月前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
1 个月前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
1 个月前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.聊天命令以及如何使用它们
1 个月前By尊渡假赌尊渡假赌尊渡假赌

热工具

Atom编辑器mac版下载

Atom编辑器mac版下载

最流行的的开源编辑器

PhpStorm Mac 版本

PhpStorm Mac 版本

最新(2018.2.1 )专业的PHP集成开发工具

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

WebStorm Mac版

WebStorm Mac版

好用的JavaScript开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)