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

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

3 ответа

Решение

LSP: получатель должен выполнить обещанные контракты.

ISP: абонент не должен зависеть от большего количества получателя, чем ему нужно.

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

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

LSP (подстановка Лискова): проблема: у вас есть переопределенный неиспользуемый / пустой метод в дочернем элементе, другими словами, ваш ребенок расширяет поведение и ему это не нужно: например:

/// LSP против ISP

class Animal {
    func fly() {
        // TODO: flying logic
    }

    func eat() {
        // TODO: eating logic
    }
}

class Cat: Animal {
    override func fly() {
        //Hi I'm a cat I cant fly,
        ///here is the Breaking of LSP, I have a different behavior
    }
}

ISP (Interface Segregation): у вас уже есть интерфейс со многими обязанностями, и разработчику не нужны все эти вещи, поэтому вам нужно разбить эти методы и перегруппировать их в реляционное поведение.

//this is bad, why, cause it have two different responsibilities
protocol Animal {
    func fly()
    func eat()
}
//to it write
protocol Flyable {
    func fly()
}
protocol Feedable {
    func eat()
}

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

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

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

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

См. Также: LSP против DIP