Как избежать нарушения принципа замещения Лискова (LSP)?

Я нахожусь в ситуации, очень похожей на то, что Стив МакКоннеллв Code Complete упоминал. . Только то, что моя проблема основана на транспортных средствах, а трайк по закону относится к категории автомобилей. Автомобили до сих пор имели четыре колеса. В любом случае, мой домен излишне сложен, поэтому легко придерживаться приведенного ниже примера с кошками.

С подозрением относитесь к классам, которые переопределяют подпрограммы и ничего не делают внутри. производная подпрограмма Обычно это указывает на ошибку в дизайне базовый класс. Например, предположим, что у вас есть класс Cat и подпрограммы Scratch() и предположим, что в конце концов вы обнаружите, что некоторые кошки без когтей и не могут поцарапать. У вас может возникнуть соблазн создать класс, производный от Cat, с именем ScratchlessCat и переопределяет Scratch() рутина ничего не делать. Этот подход представляет несколько проблем:

Он нарушает абстракцию (контракт интерфейса), представленную в Cat класс, изменив семантику его интерфейса.

Этот подход быстро выходит из-под контроля, когда вы распространяете его на другие производные классы. Что будет, если найти кошку без хвоста? Или кот, который не ловит мышей? Или кошка, которая не пьет молоко? В конце концов вы получите производные классы, такие как Без царапин, без хвоста, без мышей, без молока, кошки.

Со временем этот подход приводит к появлению кода, который сбивает с толку поддерживать, потому что интерфейсы и поведение классов-предков практически ничего не говорят о поведении их потомков.

Эту проблему можно исправить не в базовом классе, а в оригинальный класс кошек. Создайте класс Claws и включите его в Класс кошек. Корень проблемы заключался в предположении, что все кошки царапаются, так что исправьте эту проблему в источнике, а не просто перевязывайте ее назначение.

Согласно тексту из его большой книги выше. Следовать плохо

Родительский класс не обязательно должен быть абстрактным

public abstract class Cat {
   public void scratch() {
      System.out.println("I can scratch");
   }
}

Производный класс

public class ScratchlessCat extends Cat {
   @Override
   public void scratch() {
      // do nothing
   }
}

Теперь он предлагает создать еще один класс Когти, но я не понимаю, как я могу использовать этот класс, чтобы избежать нужен ScratchlessCat#Scratch.

15
задан SteveT 21 September 2012 в 14:30
поделиться