DXT
DXT

Reputation: 23

Does the example below violate Liskov Substitution Principal?

Could anybody tell me the example below violate LSP or not?

I have an example:

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");
        }
    }
}

and the subclass:

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");
        }
    }
}

and the main class:

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();
    }
}


In this example the subclass add new property called employeeCode and override method validate with additional check for it's own property employeeCode.

In the main method I create 2 objects. The first one is object of type Person and the second one is object of type Employee.

When validate person it is ok because all precondition is ok but for the employee it will throw an IllegalArgumentException because it does not match precondition

  1. Does Employee violate LSP due to add new validation on employeeCode?
  2. If 1 is yes, how can I refactor it to avoid violate LSP?
  3. If 1 is no, if I change exception from IllegalArgumentException("Employee code can not be null") to another exception NullPointerException. So does it violate LSP due to introduce new exception type in subtype (which super type does not have)?

Upvotes: 1

Views: 307

Answers (1)

tgdavies
tgdavies

Reputation: 11474

  1. No, instances of Person and Employee have exactly the same range of behaviours when validate is called. That is, calling it will either result in an IllegalArgumentException being thrown, or it won't, so no code which is calling validate and correctly handling the result of calling it on Person will fail to correctly handle the result of calling it on Employee.

  2. n/a

  3. In my opinion: As both IllegalArgumentException and NullPointerException are unchecked exceptions, they don't form part of the contract of validate, which is entitled to throw any subclass of RuntimeException it feels like. A better design would have throws ValidationException as part of the signature of validate.

As @jaco0646 says in their comment above, Java doesn't allow you to formally specify everything about a method.

Suppose I write another subclass of Person and decide that my validate() implementation will actually fix any invalid values by setting them to defaults. As we don't expect the validate() method to mutate the object (even though we have no formal way of saying that), that would violate LSP.

Upvotes: 1

Related Questions