提问者:小点点

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


有人能告诉我下面的例子是否违反了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个答案

匿名用户

> < li>

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

不适用

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

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

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