Я перешел на использование принципа проектирования и использования интерфейсов, который гласит: «просите только то, что вам нужно».
Например, если у меня есть куча типов, которые можно удалить, я сделаю Deletable
интерфейс:
interface Deletable {
void delete();
}
Тогда я могу написать общий класс:
class Deleter<T extends Deletable> {
void delete(T t) {
t.delete();
}
}
В другом месте кода я всегда буду требовать минимальной ответственности за выполнение требований клиентского кода. Так что, если мне нужно только удалить File
, я все равно буду просить Deletable
, а не File
.
Является ли этот принцип общеизвестным и уже принятым? Является ли это спорно? Это обсуждается в учебниках?
object-oriented
interfaces
solid
single-responsibility
glenviewjeff
источник
источник
Ответы:
Я действительно считаю, что это относится к тому, что Роберт Мартин называет принципом разделения интерфейсов . Интерфейсы разделены на маленькие и сжатые, так что потребители (клиенты) должны будут знать только о методах, которые им интересны. Вы можете проверить больше на SOLID .
источник
Для того, чтобы расширить свое присутствие на очень хороший ответ Вадима, я ответить на «это спорный» вопрос с «нет, на самом деле не».
В целом, сегрегация интерфейса - это хорошая вещь, поскольку сокращается общее количество «причин для изменения» различных задействованных объектов. Основной принцип заключается в том, что когда интерфейс с несколькими методами должен быть изменен, скажем, для добавления параметра к одному из методов интерфейса, тогда все потребители интерфейса должны по крайней мере перекомпилироваться, даже если они не использовали измененный метод, «Но это просто перекомпиляция!», Слышу, вы говорите; это может быть правдой, но имейте в виду, что, как правило, все, что вы перекомпилируете, должно быть удалено как часть программного патча, независимо от того, насколько значительным является изменение в двоичном файле. Эти правила были изначально концептуализированы еще в начале 90-х годов, когда средняя настольная рабочая станция была менее мощной, чем телефон в вашем кармане, 14,4 Кбод было просто невероятно, а 3,5 "1,44 МБ" дискеты "были основными сменными носителями. Даже в нынешнюю эпоху 3G / 4G пользователи беспроводного Интернета часто имеют тарифные планы с ограничениями, поэтому при выпуске обновления меньше загружаемых двоичных файлов, тем лучше.
Однако, как и все хорошие идеи, сегрегация интерфейса может быть испорчена при неправильной реализации. Во-первых, существует вероятность того, что путем разделения интерфейсов при сохранении относительно неизменным объекта, реализующего эти интерфейсы (удовлетворяющего зависимостям), вы можете получить «Гидру», родственную анти-паттерну «Объект Бога», где Всезнающая, всесильная природа объекта скрыта от зависимостей узкими интерфейсами. В итоге вы получите многоглавого монстра, которого, по крайней мере, так сложно поддерживать, как Бого-объекта, плюс затраты на поддержку всех его интерфейсов. Нет большого количества интерфейсов, которые вы не должны превышать, но каждому интерфейсу, который вы реализуете для одного объекта, следует предвосхищать, отвечая на вопрос «Вносит ли этот интерфейс вклад в объект»?
Во-вторых, интерфейс для метода может быть необязательным, несмотря на то, что может сказать вам SRP. Вы можете получить «код равиоли»; так много кусков размером с укус, что трудно проследить, чтобы выяснить, где именно все происходит на самом деле. Также нет необходимости разделять интерфейс двумя методами, если все текущие пользователи этого интерфейса нуждаются в обоих методах. Даже если одному из зависимых классов нужен только один из двух методов, обычно приемлемо не разделять интерфейс, если его методы концептуально имеют очень высокую степень сцепления (хорошими примерами являются «антонимические методы», которые являются точными противоположностями друг друга).
Разделение интерфейса должно основываться на классах, которые зависят от интерфейса:
Если от интерфейса зависит только один класс, не разделяйте его. Если класс не использует один или несколько методов интерфейса и является единственным потребителем интерфейса, скорее всего, вы не должны были раскрывать эти методы с самого начала.
Если существует более одного класса, который зависит от интерфейса, и все зависимые лица используют все методы интерфейса, не разделяйте; если вам нужно изменить интерфейс (чтобы добавить метод или изменить подпись), все текущие потребители будут затронуты изменением, независимо от того, сегрегируете вы или нет (хотя, если вы добавляете метод, который по крайней мере одному зависимому не понадобится, рассмотрите осторожно, если вместо этого изменения должны быть реализованы как новый интерфейс, возможно, наследуя от существующего).
Если существует более одного класса, зависящего от интерфейса, и они не используют все одинаковые методы, это кандидат на сегрегацию. Посмотрите на «согласованность» интерфейса; все ли методы способствуют достижению единой, очень конкретной цели программирования? Если вы можете определить несколько основных целей для интерфейса (и его разработчиков), рассмотрите возможность разделения интерфейсов вдоль этих линий, чтобы создать меньшие интерфейсы с меньшим количеством «причин для изменения».
источник
IBaz : IFoo, IBar
и требовать этого вместо этого.IFoo
иIBar
, определение составногоIFooBar
может быть хорошей идеей, но если интерфейсы тонко разделены, то в конечном итоге потребуется десятки различных типов интерфейсов. Рассмотрим следующие коллекции функций, которые могут иметь: перечислить, подсчитать число, прочитать n-й элемент, записать n-й элемент, вставить перед n-ным элементом, удалить n-й элемент, новый элемент (увеличить коллекцию и вернуть индекс нового пространства) и добавить. Девять методов: ECRWIDNA. Я мог бы описать десятки типов, которые, естественно, поддерживали бы множество различных комбинаций.