Поиск примеров / случаев, когда необходимо наследование нескольких интерфейсов (не реализация) - PullRequest
4 голосов
/ 20 марта 2012

И C #, и Java поддерживают интерфейсы, наследуемые от нескольких родителей:

public interface IMyInterface : IInterface1, IInterface2

public interface MyInterface
extends Interface1, Interface2

Я искал в документации по .NET Framework и JavaAPI примеры, когда наследование нескольких интерфейсовused.

В JavaAPI я нахожу примеры подынтерфейсов, расширяющих суперинтерфейс и один или несколько «маркерных» интерфейсов (т.е. у них нет определенных методов).Таким образом, «маркерные» интерфейсы на самом деле ничего не навязывают реализации.Я вижу выгоду от этого, особенно до введения аннотаций.

В .NET я нахожу интерфейсы, наследуемые от нескольких родителей, которые уже связаны между собой.Например, IList наследуется от ICollection и IEnumerable, но ICollection уже является потомком IEnumerable.Таким образом, принудительное выполнение IEnumerable в реализации уже выполнено с единым наследованием.

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

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

Ответы [ 4 ]

1 голос
/ 20 марта 2012

Если я понимаю, как вы описывали цепочку наследования интерфейса .NET, значит, вы ошиблись. Это простая ошибка, так как документация так выглядит. IList<T> только явно наследуется от ICollection<T>; не наследуется от ICollection<T>, IEnumerable<T> и IEnumerable. Вот фактическое определение из справочного источника:

public interface IList<T> : ICollection<T>

То же самое относится к ICollection<T>, оно наследуется только от IEnumerable<T>. Во время компиляции дерево наследования сглаживается и в некотором смысле дедуплицируется для интерфейсов. Таким образом, интерфейс, который наследует ICollection, не просто наследует этот интерфейс, который, в свою очередь, наследует IEnumerable. Скорее интерфейс будет наследовать ICollection и IEnumerable сам.

Визуальный пример:

IMine : ICollection<T> != IMine : (ICollection<T>:(IEnumerable<T>:IEnumerable))

Вместо этого это выглядит так:

IMine: ICollection<T>, IEnumerable<T>, IEnumerable

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


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

public interface IQueryable<out T> : IEnumerable<T>, IQueryable {}
public interface IOrderedQueryable<out T> : IQueryable<T>, IOrderedQueryable {}

IQueryable должен иметь контракт, в котором указано, что вы можете выполнять итерации по каждому элементу, а также возможность отличаться от простого IEnumerable в том смысле, что он один, а не все типы IEnumerable могут использоваться в IQueryProvider и статический Queryable класс.


Еще одна забавная тема в пространстве имен System.Collections.Concurrent.

public interface IProducerConsumerCollection<T> : IEnumerable<T>, ICollection

Это интересно, потому что он наследует от ICollection (не универсальный) и IEnumerable<T>, которые оба наследуются от IEnumerable. Конечно, это не проблема, но это еще один хороший пример. Если бы IProducerConsumerCollection<T> наследовал от ICollection<T> вместо его неуниверсального аналога, я уверен, что он не будет явно наследоваться от IEnumerable<T>. Он имеет размер, (старый) поведение перечислителя и методы синхронизации, определенные в ICollection, а также общее поведение перечисления, определенное в IEnumerable<T>

Есть два примера. Я нашел еще кое-что, но, думаю, этого вполне достаточно.

1 голос
/ 20 марта 2012

Если вы хотите, чтобы все объекты, реализующие ваш интерфейс, были IDisposable и IComparable .

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

IResource<T>: IDisposable, IComparable<T>, IEquatable<T>
1 голос
/ 20 марта 2012

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

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

0 голосов
/ 20 марта 2012

В Java:

Comparable часто требуется отделить от основного типа.

AbstractList подтипов AbstractCollection и List.

StringBuilder является одновременно CharSequence (интерфейс чтения) и Appendable (интерфейс записи).Я не слишком заинтересован в объединении операций чтения и записи, таких как неизменяемые значения и интерфейсы типа «говорите, не спрашивайте».

Очевидно, существуют (в основном злые) интерфейсы маркеров: Serializable, Cloneable и RandomAccess.

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

...