当前位置: 首页 > 知识库问答 >
问题:

下面的例子是否违反了Liskov替代原则?

乐正心水
2023-03-14

有人能告诉我下面的例子是否违反了LSP吗?

我有一个例子:

public class Person {
    private String name;
    private Integer age;

    public Person(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public void validate() {
        if (age == null || age < 0) {
            throw new IllegalArgumentException("Age can not be null");
        }
    }
}

和子类:

public class Employee extends Person {
    private String employeeCode;

    public Employee(String name, Integer age, String employeeCode) {
        super(name, age);
        this.employeeCode = employeeCode;
    }

    @Override
    public void validate() {
        super.validate();
        if (employeeCode == null) {
            throw new IllegalArgumentException("Employee code can not be null");
        }
    }
}

和主类:

public class Main {
    public static void main(String[] args) {
        Person person = new Person("Person", 10);
        validate(person); // will be ok. does not throw any exception

        Person employee = new Employee("Employee", 30, null);
        validate(employee); // will be throw IllegalArgumentException because subtype's employee code is null
    }

    public static void validate(Person p) {
        p.validate();
    }
}


在此示例中,子类添加名为 employeeCode 的新属性,并通过对其自己的属性 employeeCode 进行附加检查来覆盖方法验证

在main方法中,我创建了2个对象。第一个是Person类型的对象,第二个是员工类型的对象

当验证人员时,因为所有前提条件都是正确的,所以它是正确的,但是对于员工,它将抛出< code > IllegalArgumentException ,因为它与前提条件不匹配

  1. 员工是否由于在员工代码上添加新的验证而违反LSP?
  2. 如果1是,我如何重构它以避免违反LSP?
  3. 如果1为否,如果我将异常从IllegalArgumentExcgon("员工代码不能为空")更改为另一个异常NullPointerExcsion。那么它是否因为在子类型中引入了新的异常类型(哪个超级类型没有)而违反了LSP呢?

共有1个答案

汲昊空
2023-03-14

> < li>

不,当调用< code>validate时,< code>Person和< code>Employee的实例具有完全相同的行为范围。也就是说,调用它要么会导致抛出< code > IllegalArgumentException ,要么不会,因此调用< code>validate并正确处理对< code>Person调用它的结果的任何代码都不会无法正确处理对< code>Employee调用它的结果。

不适用

在我看来:由于IllegalArgumentExceptionNullPointerException都是未经检查的异常,因此它们不构成 contract的一部分,该contract有权抛出运行时异常的任何子类。更好的设计应该是将 抛出ValidationException作为 validate签名的一部分。

正如@jaco0646在上面的评论中所说,Java不允许您正式指定方法的所有内容。

假设我编写了Person的另一个子类,并决定我的va

 类似资料:
  • 我是OOP的新手。最近我读到了关于Liskov替换原理的文章。 在下面给出的代码中,Square类继承Give_区域。假设Square类与Square相关(比如有效性检查)。Give_Area给出正方形的面积(4个顶点位于圆的周长上)和圆的面积。所以,如果给我一个半径,我必须打印圆和正方形的面积(由放置在圆周长上的顶点组成)。为了得到圆的面积,我使用了一个参数。但在求平方面积时没有参数。因此,我在

  • 来自维基百科, Liskov的行为子类型概念定义了对象的可替代性概念;也就是说,如果S是T的子类型,则程序中T类型的对象可以替换为S类型的对象,而不改变该程序的任何期望属性(例如正确性)。 假设以下类层次结构: 基本抽象类-。它有一个只读属性,在后继程序中被重写。 基类的继承者-,它重写并返回灰色。 Cat的继任者-,它覆盖并返回带条纹的。 然后我们声明一个方法,参数类型为(不是)。 向该方法发送

  • 我有以下代码: 所以我们知道

  • 我正在阅读为什么Java中的数组协方差不好(为什么数组是协方差的,而泛型是不变的?)。如果是的子类型,则是的子类型。这是一个问题,因为这样的事情是可以做的: 这与“正确”实现的泛型不同。不是的子类型 我试图理解为什么它是坏的本质,并且刚刚读了关于LSP的文章。它有没有违反LSP?似乎没有明显的违规行为。

  • Liskov替换原则指出,您应该编写您的类继承,这样将子类型交换为它们的基类型就不会改变应用程序的行为。 然而,虚拟关键字字面上似乎存在,以允许子类型的行为不同于基类型。虚拟/覆盖关键字(不包括覆盖抽象成员)的大多数使用不可能违反Liskov吗?我觉得这可能比我理解的更微妙。也许这是一个“规则有时会被打破”的情况,或者原则中的“不要有不同的行为”部分有一个灰色地带。

  • 如果S是T的一个子类型,那么T类型的对象可以被S类型的对象替换。 子类有两种不同的行为(选中与未选中),在某些情况下,除非更改当前代码,否则无法用子类对象有效地替换基类用法,例如,如果编写如下代码: 这是违反吗?,为什么/为什么不?。 资料来源:http://www.oracle.com/technetwork/articles/entarch/effective-exceptions-09234