#c# #oop #inheritance #interface
#c# #ооп #наследование #интерфейс
Вопрос:
Допустим, у нас есть два интерфейса:
interface Ilayer1 : Ilayer2
{
string testMethod1();
}
interface Ilayer2
{
string testMethod2();
}
class A: Ilayer1
{
...//implement all methods of Ilayer 1 and Ilayer2
}
Итак, мои вопросы:
- Какова цель наследования интерфейса? Поскольку они могут иметь разные сигнатуры методов для реализации, так что же
Ilayer1
получается при наследовании отIlayer2
? - Мы можем просто удалить отношение наследования между
Ilayer1
иIlayer2
и просто позволить классу A реализовать оба интерфейса какclass A: Ilayer1, Ilayer2
Комментарии:
1.
IPrimate : IMammal : IVertebrate
например. Каждый из них добавляет определенные характеристики к тому, что он наследует, чего не могут другие. Например, вы также могли бы иметьIFish : IVertebrate
поскольку рыбы и млекопитающие обладают некоторыми отличными друг от друга свойствами.2. Итак, вы согласны с повторением снова и снова
Ilayer2
в каждом разработчикеIlayer1
?3. Если
ILayer1
добавляет функциональность кILayer2
илиILayer2
является чем-то, чтоILayer1
также используется (напримерIComparable
), тогда это имеет смысл. Примеры из реального мира сделали бы это более очевидным.
Ответ №1:
Это та же семантика, что и наследование между классами.
В мире ООП производный тип наследует базовый тип, когда это более конкретная версия базового типа — является ли этот тип интерфейсом или классом, принцип остается тем же.
Вот пример из .Net framework: IList
Интерфейс наследует интерфейс ICollection, который наследует интерфейс IEnumerable.
IEnumerable
Интерфейс предоставляет GetEnumerator()
метод, который необходим для перечисления с использованием foreach
цикла.
ICollection
Добавлены новые возможности: Count
свойство и CopyTo
метод.
IList
Добавляет еще больше возможностей — индексатор, методы Add
и Remove
и так далее.
Таким образом, IList
это более специфический тип an ICollection
, который является более специфическим типом an IEnumerable
.
Тот факт, что интерфейсы могут наследовать друг другу, означает, что вы можете иметь полиморфную точку зрения также на интерфейсы, а не только на классы, что может помочь значительно упростить ваш код при работе с несколькими интерфейсами, наследующими друг друга.
Еще одним преимуществом этого является тот факт, что вы можете объявлять методы расширения в интерфейсе и использовать его в любом классе, который реализует этот интерфейс прямо или косвенно, реализуя интерфейс, который его наследует — точно так же, как в классах.
Что касается вопроса о том, почему бы не удалить наследование и реализовать отдельно два интерфейса — это имело бы смысл, если бы интерфейсы не были связаны — как, например, в Control
классе (в System.Windows.Формы) — Он реализует множество интерфейсов, таких как IDropTarget
и IComponent
, которые не связаны между собой.
Ответ №2:
Один реальный пример:
interface IShape
{
double X { get; }
double Y { get; }
}
interface IAreaShape : IShape
{
double GetArea();
}
interface IPerimeterShape : IShape
{
double GetPerimeter();
}
Теперь предположим, что у вас есть Rectangle : IAreaShape, IPerimeterShape
фигура, и вы можете вычислить как ее площадь, так и периметр. Когда у вас есть объект типа IAreaShape
or IPerimeterShape
, он должен быть IShape
. Это ответ на ваш 2-й вопрос.
Теперь для вашего первого вопроса, просто предположим, для примера, что у нас есть Circle
, что я могу вычислить только площадь, но не периметр. В этом случае мы просто объявляем это Circle : IAreaShape
.
И для управления: List<IShape> shapes
может принимать как круг, так и прямоугольник и что угодно, если они реализуют IShape
(или любой производный тип IShape
). Вы можете сделать это, если вам все равно, можно ли вычислить их площадь или периметр, но вы всегда можете получить их координаты X и Y.
Ответ №3:
Ilayer1
наследуется,Ilayer2
так что это означает, что любому реализующемуIlayer1
нужно будет реализоватьtestMethod1()
иtestMethod2()
. Зачем это нужно? Почему бы и нет? Потому что мы можем? Я думаю, что в больших проектах с большим количеством интерфейсов это может стать довольно утомительным, если вам нужно указать все интерфейсы, которые какой-либо класс реализует отдельно (хотя в хорошем SOLID дизайне класс обычно в любом случае не должен реализовывать более нескольких интерфейсов). Таким образом, вы можете «группировать» интерфейсы, заставляя их реализовывать другие. Вы также можете «модифицировать» интерфейс с помощью наследования интерфейса.- Вы можете. Это зависит от вас. Хорошо иметь выбор. Используйте наследование или реализуйте интерфейсы по отдельности. Это зависит от вас.
Интерфейсы могут наследоваться от других интерфейсов. Класс может включать интерфейс несколько раз через базовые классы, которые он наследует, или через интерфейсы, которые наследуют другие интерфейсы. Однако класс может предоставить реализацию интерфейса только один раз и только в том случае, если класс объявляет интерфейс как часть определения класса (
class ClassName : InterfaceName
). Если интерфейс унаследован из-за того, что вы унаследовали базовый класс, который реализует интерфейс, базовый класс обеспечивает реализацию элементов интерфейса. Однако производный класс может переопределять любые элементы виртуального интерфейса вместо использования унаследованной реализации. Источник