Есть ли принципиальное различие между принципом замещения Лисков (LSP) и принципом разделения интерфейсов (ISP)? В конечном счете, оба ручаются за разработку интерфейса с общими функциями и представляют новый интерфейс, когда у вас есть специальное назначение функций.
Разница между принципом подстановки лисков и принципом разделения интерфейсов
Ответы (3)
LSP: Получатель должен соблюдать контракты, которые он обещает.
Интернет-провайдер: вызывающий абонент не должен зависеть от интерфейса получателя больше, чем ему нужно.
Где они подходят: если вы применяете ISP, вы используете только часть полного интерфейса приемника. Но, согласно LSP, получатель все равно должен учитывать этот фрагмент.
Если вы не сможете применить ISP, может возникнуть соблазн нарушить LSP. Поскольку этот метод не имеет значения, на самом деле он не будет вызываться.
Оба они являются ТВЕРДЫМИ принципами
- 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()
}
LSP управляет отношениями между родительским и дочерним классами (т. е. иерархическими отношениями). В нем рассказывается, как реализовать API.
ISP регулирует отношения между родительским и клиентским классами (т. е. отношения производитель/потребитель). Он сообщает вам, когда внедрять API.
Рассмотрим интерфейс с сотней методов. Дочерний класс может реализовать все сто, не нарушая контрактов, определенных любым из них, и, таким образом, удовлетворяя замене Лискова; но трудно представить, что каждому клиенту потребуются все эти методы, поэтому разделение интерфейса почти наверняка будет нарушено.
И наоборот, интерфейс только с одним методом обязательно удовлетворяет разделению интерфейсов; но если реализация не подчиняется этому контракту на один метод, то замена Лискова нарушается.
См. также: LSP и DIP