Я в ситуации, очень похожей на то, что Steve McConnell's в Code Complete упомянули. Только в том, что моя проблема основана на транспортных средствах и Trike, оказывается, по закону попадает в категорию автомобилей. До сих пор у автомобилей было четыре колеса. В любом случае мой домен излишне сложный, поэтому его легко придерживаться примерами кошек ниже.Как я могу избежать нарушения Принципа замещения Лискова (LSP)?
с подозрением к классам, которые переопределяют процедуру и не делать ничего внутри производный рутина Это обычно указывает на ошибку в конструкции базового класса. Например, предположим, что у вас есть класс Cat и подпрограмма Scratch(), и предположим, что вы в конце концов узнаете, что некоторые кошки объявлены и не могут поцарапать. Возможно, возникнет соблазн создать класс , полученный из Cat с именем ScratchlessCat, и переопределить процедуру Scratch() , чтобы ничего не делать. Этот подход представляет ряд проблем:
Он нарушает абстракцию (контракт интерфейса), представленный в классе Cat , путем изменения семантики его интерфейса.
Этот подход быстро выходит из-под контроля, когда вы распространяете его на другие производные классы . Что происходит, когда вы найдете кошку без хвоста? Или кошка, которая не ловит мышей? Или кот, который не пьет молоко? В конце концов вы получите производные классы, такие как ScratchlessTaillessMicelessMilklessCat.
Со временем этот подход порождает код, который вводит в заблуждение , потому что интерфейсы и поведение классов-предшественников практически не влияют на поведение их потомков.
Место для исправления этой проблемы отсутствует в базовом классе, но в исходном классе Cat. Создайте класс Claws и включите его в класс Cats. Коренной проблемой было предположение, что все кошки царапины, так исправить эту проблему у источника, а не просто перевязать ее по адресу адресата.
Согласно тексту из его великой книги выше. После плохой
родительский класс не должен быть абстрактным
public abstract class Cat {
public void scratch() {
System.out.println("I can scratch");
}
}
производный класс
public class ScratchlessCat extends Cat {
@Override
public void scratch() {
// do nothing
}
}
Теперь он предлагает создать еще один класс Claws
, но я не понимаю, как может Я использую этот класс, чтобы избежать необходимости в ScratchlessCat#Scratch
.
Пример Cat является хорошей иллюстрацией LSP. Узнав о LSP, я был поражен, сколько плохих примеров и сколько недоразумений существует на SO и других сайтах. – SteveT