В чем причина принципа разделения интерфейса?

Принцип сегрегации интерфейса (ISP) гласит, что многие клиентские интерфейсы лучше, чем один универсальный интерфейс. Почему это важно?

7 ответов

Решение

ISP заявляет, что:

Клиенты не должны зависеть от методов, которые они не используют.

ISP относится к важным характеристикам - сцепление и сцепление.
В идеале ваши компоненты должны быть в высшей степени адаптированы. Это повышает надежность кода и ремонтопригодность.

Принудительный провайдер дает вам следующие бонусы:

  • Высокая сплоченность - лучшая понятность, надежность
  • Низкое сцепление - лучшая ремонтопригодность, высокая устойчивость к изменениям

Если вы хотите узнать больше о принципах разработки программного обеспечения, получите экземпляр книги Agile Software Development, Principles, Patterns и Practices.

Разделение интерфейса - это "Я" по принципу SOLID, прежде чем копать слишком глубоко с первым, давайте объясним, что означает последнее.

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

Почему я должен заботиться о твердом программировании?

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

Принцип сегрегации интерфейса.

Зная, что мы знаем, что такое принципы SOLID, мы можем подробнее узнать о принципе разделения интерфейса, но что именно говорит разделение интерфейса?

"Клиентов не следует заставлять применять ненужные методы, которые они не будут использовать"

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

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

Увидеть! Это намного лучше! Применение этого принципа позволит вам иметь низкое сцепление, что способствует лучшей ремонтопригодности и высокой устойчивости к изменениям. Таким образом, вы можете реально использовать использование интерфейсов и реализацию методов, когда вам это действительно нужно. Теперь давайте рассмотрим менее абстрактный пример, скажем, вы объявили интерфейс под названием Reportable

public interface Reportable {

        void printPDF();
        void printWord();
        void printExcel();
        void printPPT();
        void printHTML();


}

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

Не забывайте про простоту и не повторяйте себя, и вы обнаружите, что уже используете этот принцип, не зная.

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

Статья Роберта Мартина на эту тему дает объяснение, которое упоминается реже:

Обратная сила, применяемая клиентами к интерфейсам.

Если два класса напрямую зависят от двух разных методов третьего класса, это увеличивает вероятность того, что изменения одного из первых двух классов повлияют на другой.

Предположим, у нас есть три класса: Red, Green, а также Blue,

Red а также Green оба зависят Blue, но каждый зависит от другого метода. Это означает, что Red зависит от одного метода Blue но не использует другой метод. Точно так же, Green зависит от Blue, но использует только один метод, а не другой.

Нарушение принципа заключается в Red а также Green потому что каждый зависит от класса - Blue - но не использует хотя бы один из его методов.

Какую проблему это может создать?

  • мне нужно изменить Redи я тоже меняю Blue для удовлетворения потребностей Red,
  • Я не изменил конкретный метод в Blue тот Green зависит, но, тем не менее, Green зависит от Blue и я изменился Blue, который еще может повлиять Green,
  • Поэтому мои изменения в Red имеют потенциал для воздействия Blue потому что они привели меня к изменению класса, от которого зависят оба.

Это "обратная сила". Мы иногда меняем класс из-за потребностей своих клиентов. Если у этого класса разные клиенты, которые используют его для разных целей, мы рискуем повлиять на них.

Как уже говорилось, простое определение принципа разделения интерфейса:

Ни один клиент не должен зависеть от методов, которые он не использует.

Между этим и вышеприведенным пунктом из статьи Роберта Мартина очевидно, что многие объяснения провайдера на самом деле говорят о других принципах.

  • Классы или интерфейсы с множеством методов нежелательны, но не специально из-за провайдера. Они могут нарушать Единую ответственность. Но нарушение ISP не в большом интерфейсе или большом классе - это в классах, которые зависят от большого интерфейса, если они не используют все его методы. Если они используют все методы, это все еще звучит грязно, но это не имеет никакого отношения к провайдеру.
  • Классы, которые реализуют интерфейс, но генерируют исключения для определенных методов, являются плохими, но это также не ISP. ISP - это классы, которые зависят от интерфейсов, а не классы, которые реализуют интерфейсы.

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

Принцип разделения интерфейса гласит, что клиенты не должны принуждать к реализации интерфейсов, которые они не используют

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

Более того, каждый раз, когда новый интерфейс добавляется к базовому классу, этот интерфейс должен быть реализован (или разрешен по умолчанию) в производных классах. Действительно, связанная практика заключается в добавлении этих интерфейсов к базовому классу в виде нулевых виртуальных функций, а не чисто виртуальных функций; в частности, чтобы производные классы не были обременены необходимостью их реализации. Как мы узнали во второй статье этого столбца, такая практика нарушает принцип замещения Лискова (LSP), что приводит к проблемам в обслуживании и повторном использовании.

Более того, говорить, что клиент не должен реализовывать методы, которые он не использует, даже не имеет смысла. Клиенты интерфейса не реализуют его методы.

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

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

Этот принцип в первую очередь служит двойным целям

  • Чтобы сделать код более читабельным и управляемым.

  • Способствует единоличной ответственности за занятия (высокая сплоченность). Конечно, почему у класса должен быть метод, который не оказывает никакого поведенческого воздействия? Почему бы просто не удалить его. Вот о чем провайдер

Есть несколько вопросов, которые дизайнер должен задать с заботами ISP

  • Что можно достичь с провайдером
  • Как проанализировать уже существующий код на предмет нарушений интернет-провайдера

Чтобы продолжить это обсуждение, я также должен добавить, что этот принцип не является "принципом" в самом строгом смысле, потому что при определенных обстоятельствах применение ISP к дизайну, вместо того, чтобы способствовать удобочитаемости, может сделать структуру объекта нечитаемой и загроможденной ненужный код. Вы можете хорошо наблюдать это в пакете java.awt.event

Больше в моем блоге: http://design-principle-pattern.blogspot.in/2013/12/interface-segregation-principle.html

Интернет-провайдер важен.

Основная идея провайдера: Клиент не должен зависеть от методов, которые он не использует.

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

См. Ниже вопрос SE для примера кода:

Принцип разделения интерфейса - программа для интерфейса

Преимущества:

  1. Гибкость: в отсутствие ISP у вас есть один общий интерфейс FAT и множество классов, реализующих его. Предположим, что у вас было 1 интерфейс и 50 классов. В случае изменения интерфейса все 50 классов должны изменить свою реализацию.

    С ISP вы разделите общий интерфейс FAT на мелкие гранулированные небольшие интерфейсы. Если в небольшом гранулированном интерфейсе есть изменения, это повлияет только на классы, реализующие этот интерфейс.

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

Чтобы избежать попыток регрессии, когда меняется только один клиент или один клиент. Если вы объединили все свои методы поведения в одном БОЛЬШОМ интерфейсе, просто подумайте о том, как вы в конечном итоге будете тестировать все фрагменты кода, на которые ссылался только этот интерфейс, даже когда произошли только небольшие изменения.

Более подробное объяснение см. В статье, посвященной принципу разделения интерфейса.

Другие вопросы по тегам