О принципе разделения интерфейсов (ISP)

Сегодня я объясню принцип разделения интерфейса (ISP),этот принцип очень похож на LSP,поэтому не путайте сLSP, поэтому я объясню о том, чем отличаются эти два принципа.

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

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

Принцип разделения интерфейсов (ISP): клиент не должен зависеть от интерфейсов, которые он не использует.

Давайте перейдем к реализации, у нас есть интерфейс с именем StudentActivities, который определяет различные методы, связанные с действиями учащихся:

interface StudentActivities {
    fun joinClub(club: String)
    fun joinSportsTeam(sportsTeam: String)
    fun attendEvent(event: String)
    fun volunteerForEvent(event: String)
    fun joinStudyGroup(subject: String)
}

у нас также есть класс Student, который реализует этот интерфейс, как показано ниже:

class Student : StudentActivities {
    override fun joinClub(club: String) {
        // join the specified club
    }

    override fun joinSportsTeam(sportsTeam: String) {
        // join the specified sports team
    }

    override fun attendEvent(event: String) {
        // attend the specified event
    }

    override fun volunteerForEvent(event: String) {
        // volunteer for the specified event
    }

    override fun joinStudyGroup(subject: String) {
        // join the specified study group
    }
}

В этом примере вы заметите, что класс Student вынужден реализовать все методы интерфейса StudentActivities, даже если учащегося могут не интересовать все действия, определенные в интерфейсе. Это нарушает принцип разделения интерфейса, потому что интерфейс слишком широкий и несвязный.

Теперь давайте рефакторинг к правильному приведенному выше примеру, мы можем разбить интерфейс StudentActivities на меньшие, более сфокусированные интерфейсы, которые клиентам легче использовать:

interface ClubActivities {
    fun joinClub(club: String)
}

interface SportsActivities {
    fun joinSportsTeam(sportsTeam: String)
}

interface EventActivities {
    fun attendEvent(event: String)
    fun volunteerForEvent(event: String)
}

interface StudyGroupActivities {
    fun joinStudyGroup(subject: String)
}

class Student : ClubActivities, SportsActivities, EventActivities, StudyGroupActivities {
    override fun joinClub(club: String) {
        // join the specified club
    }

    override fun joinSportsTeam(sportsTeam: String) {
        // join the specified sports team
    }

    override fun attendEvent(event: String) {
        // attend the specified event
    }

    override fun volunteerForEvent(event: String) {
        // volunteer for the specified event
    }

    override fun joinStudyGroup(subject: String) {
        // join the specified study group
    }
}

В этой рефакторинговой версии мы разделили интерфейс StudentActivities на четыре меньших, более целенаправленных интерфейса: ClubActivities, SportsActivities, EventActivities и StudyGroupActivities. Класс Student теперь реализует только те интерфейсы, которые имеют отношение к его поведению.

Это соответствует принципу разделения интерфейсов, поскольку клиенты, которым требуется только конкретное подмножество действий, определенных в интерфейсах, теперь могут зависеть только от соответствующих меньший интерфейс, вместо того, чтобы зависеть от более крупного, менее связанного интерфейса, который содержит методы, которые им не нужны.

Спасибо, что нашли время прочитать эту статью. Я надеюсь, что мое письмо было информативным и наводящим на размышления. В следующей статье я объясню принцип инверсии зависимостей (DIP). Удачного кодирования всем вам.

Предыдущая статья о SOLID:

Принцип единой ответственности (SRP): https://medium.com/arpalar-tech/solid-from-zero-to-potato-e7b5cfe8c7a1

Открытый/закрытый принцип (OCP): https://medium.com/arpalar-tech/solid-from-zero-to-potato-2-5a4c17bd8ec8

Принцип замещения Лисков (LSP): https://medium.com/arpalar-tech/solid-from-zero-to-potato-3-94d6f63dbbfe