Интерфейсы являются множественным наследованием. На самом деле, я полагал бы, что тип Java/C# соединяет интерфейсом с "надлежащей" реализацией множественного наследования. Принуждение множественного наследования с помощью интерфейсов, скорее тогда разрешение наследования от нескольких реальных или абстрактных классов вынуждают разработчика использовать состав/делегацию для повторного использования кода. Наследование никогда не должно использоваться для повторного использования кода, и отсутствие C++ вводят разработчиков сил множественного наследования для предложения лучше разработанных классов.
Я почти не упускаю множественное наследование в C #.
Если вы используете множественное наследование для определения реальной модели предметной области, то, по моему опыту, вы часто можете создать одинаково хороший дизайн, используя одиночное наследование и несколько хороших шаблонов дизайна.
Большинство мест, где я считаю, что множественное наследование имеет реальную ценность, - это те места, где это не сам домен, а некоторые ограничения технологии / инфраструктуры, требующие использовать MI. Реализация COM-объектов с использованием ATL - это очень хороший пример использования множественного наследования для реализации всех необходимых интерфейсов, необходимых COM-объекту, и элегантное решение уродливой (по сравнению с .NET) технологии. Элегантно с точки зрения того, что это фреймворк C ++!
Однако сейчас у меня есть ситуация, когда я мог бы использовать множественное наследование. У меня есть один класс, который должен наследовать функции от какого-то другого объекта домена, но он также должен быть доступен для вызовов между доменами приложений. Это означает, что он ДОЛЖЕН наследоваться от MarshalByRefObject. Итак, в этом конкретном случае я действительно хотел бы получить как от MarshalByRefObject, так и от моего конкретного объекта домена. Однако это невозможно, поэтому мой класс должен реализовать тот же интерфейс, что и мой объект домена, и переадресовывать вызовы агрегированному экземпляру.
Но это, как я уже сказал, случай, когда технология / фреймворк накладывает ограничение, а не сама модель предметной области.
У меня есть один класс, который должен наследовать функции от какого-то другого объекта домена, но он также должен быть доступен для вызовов между доменами приложений. Это означает, что он ДОЛЖЕН наследоваться от MarshalByRefObject. Итак, в этом конкретном случае я действительно хотел бы получить как от MarshalByRefObject, так и от моего конкретного объекта домена. Однако это невозможно, поэтому мой класс должен реализовать тот же интерфейс, что и мой объект домена, и переадресовывать вызовы агрегированному экземпляру.Но это, как я уже сказал, случай, когда технология / фреймворк накладывает ограничение, а не сама модель предметной области.
У меня есть один класс, который должен наследовать функции от какого-то другого объекта домена, но он также должен быть доступен для вызовов между доменами приложений. Это означает, что он ДОЛЖЕН наследоваться от MarshalByRefObject. Итак, в этом конкретном случае я действительно хотел бы получить как от MarshalByRefObject, так и от моего конкретного объекта домена. Однако это невозможно, поэтому мой класс должен реализовать тот же интерфейс, что и мой объект домена, и переадресовывать вызовы агрегированному экземпляру.Но это, как я уже сказал, случай, когда технология / фреймворк накладывает ограничение, а не сама модель предметной области.
Я действительно хотел бы получить как от MarshalByRefObject, так и от моего конкретного объекта домена. Однако это невозможно, поэтому мой класс должен реализовать тот же интерфейс, что и мой объект домена, и переадресовывать вызовы агрегированному экземпляру.Но это, как я уже сказал, случай, когда технология / фреймворк накладывает ограничение, а не сама модель предметной области.
Я действительно хотел бы получить как от MarshalByRefObject, так и от моего конкретного объекта домена. Однако это невозможно, поэтому мой класс должен реализовать тот же интерфейс, что и мой объект домена, и переадресовывать вызовы агрегированному экземпляру.Но это, как я уже сказал, случай, когда технология / фреймворк накладывает ограничение, а не сама модель предметной области.
Я говорю «нет» до тех пор, пока алмазная проблема (большая причина того, почему множественное наследование с классами - это плохо) не будет решена должным образом, и если решение так же хорошо, как использование интерфейсов. Короче говоря, проблема бриллианта в основном связана с потенциальной неоднозначностью данных, методов и событий в классах из-за множественного наследования через классы.
P / S Вы «редко» избегаете крайне необходимого программного решения только потому, что оно сложно. "Сложность" не может служить оправданием отсутствия множественного наследования. Многопоточность сложна, но она доступна на C #. Отсутствие множественного наследования связано с проблемой алмаза ( http://en.wikipedia.org/wiki/Diamond_problem ).