Переопределение разрывов Принцип подстановки Лискова, если вы изменяете любое поведение, определенное базовым методом. Это означает, что:
- Самая слабая предпосылка для
дочерний метод должен быть не сильнее
чем для базового метода.
- Постусловие для дочернего метода
подразумевает постусловие для
родительский метод. Где постусловие
состоит из: а) все стороны
эффекты, вызванные выполнением метода и b)
тип и значение возвращаемого выражения.
Из этих двух требований вы можете подразумевать, что любая новая функциональность в дочернем методе, которая не влияет на то, что ожидается от супер-метода, не нарушает принцип. Эти условия позволяют вам использовать экземпляр подкласса, где требуется экземпляр суперкласса.
Если эти правила не соблюдаются, класс нарушает LSP. Классическим примером является следующая иерархия: класс Point(x,y)
, класс ColoredPoint(x,y,color)
, который расширяет Point(x,y)
, и переопределенный метод equals(obj)
в ColoredPoint
, который отражает равенство по цвету. Теперь, если у каждого есть экземпляр Set<Point>
, он может предположить, что две точки с одинаковыми координатами равны в этом наборе. Что не так с переопределенным методом equals
, и, в общем, просто невозможно расширить экземплярный класс и добавить аспект, используемый в методе equals
, не нарушая LSP.
Таким образом, каждый раз, когда вы нарушаете этот принцип, вы неявно вводите потенциальную ошибку, которая выявляет, когда не удовлетворен инвариант для родительского класса, ожидаемый кодом. Однако в реальном мире часто не существует очевидного проектного решения, которое не нарушает LSP, поэтому можно использовать, например, аннотацию класса @ViolatesLSP
, чтобы предупредить клиента о том, что небезопасно использовать экземпляры класса в полиморфном наборе или в любые другие случаи, основанные на принципе подстановки Лискова.