Разница между принципом подстановки лисков и принципом разделения интерфейсов

Есть ли принципиальное различие между принципом замещения Лисков (LSP) и принципом разделения интерфейсов (ISP)? В конечном счете, оба ручаются за разработку интерфейса с общими функциями и представляют новый интерфейс, когда у вас есть специальное назначение функций.




Ответы (3)


LSP: Получатель должен соблюдать контракты, которые он обещает.

Интернет-провайдер: вызывающий абонент не должен зависеть от интерфейса получателя больше, чем ему нужно.

Где они подходят: если вы применяете ISP, вы используете только часть полного интерфейса приемника. Но, согласно LSP, получатель все равно должен учитывать этот фрагмент.

Если вы не сможете применить ISP, может возникнуть соблазн нарушить LSP. Поскольку этот метод не имеет значения, на самом деле он не будет вызываться.

person Jon Reid    schedule 03.02.2019
comment
Термин получатель меня сбивает с толку. Не могу понять. Не могли бы вы назвать это как-то иначе? подтип? - person ClemC; 25.11.2019
comment
Можно ли продолжить это следующим образом: замена Лисков касается дизайна подтипов, тогда как разделение интерфейсов касается дизайна базовых типов.? - person ClemC; 25.11.2019
comment
Под получателем я подразумеваю объект, получающий сообщение. Это может быть или не быть подтипом. Да, я думаю, что ваша характеристика имеет смысл относительно подтипа и базового типа. - person Jon Reid; 25.11.2019

Оба они являются ТВЕРДЫМИ принципами

  • LSP (подстановка Лискова): этот принцип требует от вас убедиться, что все дочерние классы ведут себя так же, как и родительский класс. например: если у вас есть класс Device и у него есть функция callBaba(), которая получает номер телефона вашего отца, а затем звонит ему, поэтому вы должны убедиться, что метод callBaba() во всех подклассах Device выполняет одну и ту же работу. если какой-либо из подклассов Device имеет другое поведение внутри callBaba(), это означает, что вы нарушили LSP

Пример кода, нарушающего принцип Лискова.

class Device {
    func callBaba() {
        print("I will find your father and I will call him")
    }
}

class Calculator: Device {
    override func callBaba() {
      print("Sorry, I don't have this functionality ")
    }
}

Решение

interface CanCall {
            func callBaba()
        }
        class Device {
            // all basic shared functions here.
        }

        class Calculator: Device {
            // all functions that calculator can do + Device
        }
        class SmartPhone: Device implements CanCall {
            // all smartphone stuff
            func callBaba() {
                print("I will find your father and I will call him")
            }
        }
  • ISP (разделение интерфейсов): просит вас создать другой интерфейс для разных обязанностей, другими словами, не группируйте несвязанное поведение в одном интерфейсе, вы нарушаете работу ISP, если у вас уже есть интерфейс со многими обязанностями, а разработчик не нужно все это

это нарушает принцип интернет-провайдера, потому что у него две разные обязанности

  protocol Animal {
        func fly()
        func eat()
    }

Решение

protocol Flyable {
    func fly()
}
protocol Feedable {
    func eat()
}
person Abuzeid    schedule 20.07.2019
comment
Мне кажется то же самое? оба решают проблему, разделяя функции на разные интерфейсы или разные абстрактные классы. - person Jonathan; 26.11.2020
comment
@Jonathan Мне кажется, то же самое: D - person Dardan; 17.02.2021
comment
@jonathan, у вас может быть интерфейс с одной функцией и все равно нарушить его цель. Представьте, что я реализую интерфейс Flyable и добавляю логику плавания в метод fly(). Разделение интерфейса уже в порядке, потому что я могу разделить его еще больше, но LSP не работает, потому что я не добавляю правильное поведение - person AFP_555; 30.05.2021
comment
Они оба одинаковы. Невозможно узнать, делает ли он то, что намеревается сделать, без фактического модульного тестирования и получения вывода. - person Jonathan; 30.05.2021
comment
@ Джонатан, я приведу простой пример. Представьте, что у меня есть класс Duck с абстрактным методом fly() и RubberDuck, который наследуется от этого класса. RubberDuck не может летать, поэтому вместо полета он выдает исключение в этом методе. Это также нарушает LSP, потому что мы не добавляем ожидаемое поведение, мы просто выбрасываем исключение. Или представьте, что мы добавляем плавающую логику в метод fly(), что также нарушает LSP. - person AFP_555; 03.06.2021
comment
@Jonathan Проще говоря, LSP - это проверка того, делают ли методы то, что они должны делать. Интернет-провайдер не зависит от большего количества методов, чем необходимо. Между этими двумя вещами существует ОГРОМНОЕ совпадение, на самом деле, совпадений больше, чем различий, но это не одно и то же. Это похоже на многие паттерны, например, Стратегический паттерн очень похож на паттерн Мост, но у них другое предназначение. Структурно они одинаковы, они делают то же самое в поведении, но идея, лежащая в их основе, отличается. Обычно, если LSP не работает, ISP тоже не работает, но не всегда. - person AFP_555; 03.06.2021
comment
если метод не делает то, что он должен делать, он также делает недействительным IPS, потому что вы должны наследовать только интерфейсы, которые будет использовать класс. - person Jonathan; 03.06.2021

LSP управляет отношениями между родительским и дочерним классами (т. е. иерархическими отношениями). В нем рассказывается, как реализовать API.

ISP регулирует отношения между родительским и клиентским классами (т. е. отношения производитель/потребитель). Он сообщает вам, когда внедрять API.

Рассмотрим интерфейс с сотней методов. Дочерний класс может реализовать все сто, не нарушая контрактов, определенных любым из них, и, таким образом, удовлетворяя замене Лискова; но трудно представить, что каждому клиенту потребуются все эти методы, поэтому разделение интерфейса почти наверняка будет нарушено.

И наоборот, интерфейс только с одним методом обязательно удовлетворяет разделению интерфейсов; но если реализация не подчиняется этому контракту на один метод, то замена Лискова нарушается.

См. также: LSP и DIP

person jaco0646    schedule 29.12.2020
comment
Самый лучший и ясный ответ - person Maksym Pecheniuk; 23.06.2021