Як перевірити принцип заміщення Ліскова в ієрархії спадкування?


14

Натхненний цією відповіддю:

Принцип заміщення Ліскова вимагає цього

  • Передумови не можна посилити в підтипі.
  • Послідовності не можуть бути ослаблені в підтипі.
  • Інваріанти супертипу повинні зберігатися в підтипі.
  • Обмеження історії ("правило історії"). Об'єкти вважаються модифікованими лише завдяки їх методам (інкапсуляція). Оскільки підтипи можуть вводити методи, відсутні в супертипі, то введення цих методів може дозволити зміни стану підтипу, які неприпустимі в супертипі. Обмеження історії забороняє це.

Я сподівався, що хтось опублікує ієрархію класів, яка порушує ці 4 пункти, і як їх вирішити відповідно.
Я шукаю детальне пояснення для навчальних цілей щодо того, як визначити кожен із 4-х пунктів в ієрархії та найкращий спосіб його виправити.

Примітка.
Я сподівався опублікувати зразок коду для роботи людей, але саме питання полягає в тому, як визначити несправні ієрархії :)


Є кілька інших прикладів порушення LSP у відповідях на це питання
ТА

Відповіді:


17

Це набагато простіше, ніж ця цитата робить її звуковою, точною, як є.

Дивлячись на ієрархію спадкування, уявіть метод, який отримує об'єкт базового класу. Тепер запитайте себе, чи існують припущення, що хтось, хто редагує цей метод, може зробити це недійсним для цього класу.

Наприклад ( спочатку його бачили на сайті дядька Боба ):

public class Square : Rectangle
{
    public Square(double width) : base(width, width)
    {
    }

    public override double Width
    {
        set
        {
            base.Width = value;
            base.Height = value;
        }
        get
        {
            return base.Width;
        }
    }

    public override double Height
    {
        set
        {
            base.Width = value;
            base.Height = value;
        }
        get
        {
            return base.Height;
        }
    }
}

Здається, досить справедливо, правда? Я створив спеціальний вид Прямокутник під назвою Квадрат, який стверджує, що Ширина повинна дорівнювати Висоті в усі часи. Квадрат - це прямокутник, тому він відповідає принципам ОО, чи не так?

Але зачекайте, що робити, якщо хтось зараз пише цей метод:

public void Enlarge(Rectangle rect, double factor)
{
    rect.Width *= factor;
    rect.Height *= factor;
}

Не круто. Але немає причин, щоб автор цього методу мав знати, що може виникнути потенційна проблема.

Кожен раз, коли ви отримуєте один клас з іншого, подумайте про базовий клас та про те, що люди можуть припустити про нього (наприклад, "він має ширину та висоту, і обидва вони будуть незалежними"). Тоді подумайте, "чи залишаються ці припущення в моєму підкласі?" Якщо ні, переосмислити дизайн.


Дуже хороший і тонкий приклад. +1. Що ви можете зробити, це зробити Збільшити метод класу Прямокутник і замінити його в класі Square.
marco-fiset

@ marco-fiset: Я б швидше бачив, як Квадрат і Прямокутник роз'єднані, Квадрат із лише одним виміром, але кожен реалізує IResizable. Це правда, що якби існував метод Draw, вони були б подібними, але тоді я вважаю за краще, щоб вони обоє інкапсулювали клас RectangleDrawer, який включає загальний код.
пдр

1
Я не думаю, що це хороший приклад. Проблема полягає в тому, що квадрат не має ширини чи висоти. Він просто має довжину боків. Проблеми не було б, якби ширина і висота були лише читабельні, але в цьому випадку вони підлягають запису. Під час введення модифікованого стану підтримувати LSP завжди набагато складніше.
SpaceTrucker

@pdr Дякую за приклад, але щодо 4-х умов, про які я згадував у своєму дописі, яка частина Squareкласу їх порушує?
Songo

1
@Songo: це обмеження історії. Краще поясніть тут: blackwasp.co.uk/LSP.aspx "За своєю природою підкласи включають усі методи та властивості їхніх суперкласів. Вони також можуть додавати інших членів. Обмеження історії говорить про те, що нові або модифіковані члени не повинні змінювати стан об'єкта таким чином, який би не було дозволено базовим класом . Наприклад, якщо базовий клас представляє об'єкт із фіксованим розміром, підклас не повинен дозволяти змінювати цей розмір. "
пдр
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.