Интерфейсы и множественное наследование. Определение интерфейса Реализация интерфейсов. Некоторые стандартные интерфейсы среды .NET Framework.
ИНТЕРФЕЙСЫ И МНОЖЕСТВЕННОЕ НАСЛЕДОВАНИЕ
Определение интерфейса
В ООП иногда требуется определить, что класс должен делать, а не как он будет это делать. Один из механизмов реализации этой идеи – это абстрактные методы. Абстрактные метод задаёт лишь интерфейс метода, но не способ его реализации. Идея абстрактных классов и методов в C# развивается далее путём отделения интерфейса класса от его реализации.
Интерфейсы позволяют сделать классы более обобщёнными и гибкими. Они напоминают абстрактные классы, у которых все члены абстрактные.
Класс может содержать ссылку на другой класс. Например: класс Otrezok содержит ссылку на Point. Такое соотношение объектов в программировании называется «Содержит». Один класс может расширить другой класс с помощью наследования. Это отношение называется «Является». Например: класс Circle наследуется от класса Point.
Интерфейсы реализуют ещё одно отношение: «Может_использоваться как». Интерфейс можно рассматривать как класс-сервер, а классы, которые его используют можно рассматривать как классы-клиенты.
Интерфейс может содержать только определение (объявление) событий, методов, свойств, индексаторов, а их реализация должна находиться в классе, который реализует интерфейс. Интерфейс не может содержать константы, члены-переменные, конструкторы, деструкторы, статические члены.
Итак, интерфейс определяет стандарт, которому должен удовлетворять использующий его класс, то есть интерфейс отражает поведение класса.
Когда интерфейс определён, его может реализовать любое количество классов. При этом один класс может реализовать любое количество интерфейсов, но класс обязан реализовать все члены всех интерфейсов. Если какой-то метод интерфейса не будет иметь реализации, то произойдёт исключение.
Применение интерфейсов реализуют идею ООП – полиморфизм: «Один интерфейс – много методов».
Объявление интерфейса
Интерфейс определяется с помощью ключевого слова interface (Меню àПроект à Добавить элемент à Интерфейс). Все члены интерфейса считаются открытыми (public).
Формат объявления интерфейса:
interface Имя_Интерфейса //начинать с буквы I
{
//Тело интерфейса:
Тип_возврата Имя_метода_1 (Список_параметров);
Тип_возврата Имя_метода_2 (Список_параметров);
...
Тип_возврата Имя_метода_n (Список_параметров);
Тип_элемента Имя_свойства
{
get;//set-аксессор - не бывает!
}
//Могут быть индексаторы и события
}
Задание: В проекте «Наследование» создать интерфейс, который определяет количество вершин геометрической фигуры, его имя ITop.
//В проекте «Наследование»:
interface ITop
{
byte GetTops(); //Метод, который возвращает количество вершин
}
Создавать объекты интерфейса с помощью new НЕЛЬЗЯ, будет ошибка.
//В Main():
ITop ObI = new ITop();
Интерфейс – это не класс, это какой-то общий (абстрактный) тип. Интерфейсы не приносят пользы, если они не используются классами или структурами. Интерфейсы широко используются в обобщённом программировании при создании коллекций данных.
Реализация интерфейсов
Чтобы реализовать интерфейс, нужно после имени класса через двоеточие указать Имя_базового_класса, Имя_интерфейса. Если интерфейсов несколько, то их требуется указывать через запятую.
Задание: Реализовать интерфейс ITop в классе Rectangle.
class Rectangle : Figure, ITop
{
public byte GetTops()
{
return 4;
}
…
}
В остальных классах, кроме круга (у круга нет вершин), реализация интерфейса аналогична.
class Triangle : Figure, ITop
{
public byte GetTops()
{
return 3;
}
…
}
Нужна ли реализация интерфейса в классе Kwadrat?
Способы вызова интерфейса
· Вызов на уровне объекта.Это самый простой вызов, так как Имя_класса известно, значит члены интерфейса вызываются как обычные методы, то есть через точку.
//В Main():
Console.WriteLine("У прямоугольника "+Rt1.GetTops()+" вершины.");
//Выполнить!
Console.WriteLine("У квадрата " + Kw1.GetTops() + " вершины.");
//Выполнить!
Console.WriteLine("У треугольника " + Tr1.GetTops() + " вершины.");
//Выполнить!
При работе с массивом объектов класса Figure в текущий момент времени точное имя класса не известно, так как доступ к элементам массива происходит через инструкцию mas[i]. В этом случае элементом массива mas[i] может быть и объект класса Circle, а он не реализует интерфейс ITop.
Как же получить информацию: «Поддерживает ли класс интерфейс?»
· Вызов члена интерфейса с обработкой исключений (блоки try и catch).
//В Main():
Circle Kr = new Circle(10);
ITop pr1; //Переменная типа интерфейс ITop
try
{
pr1 = (ITop)Kr;
Console.WriteLine("У круга вершин " + pr1.GetTops());
}
catch (InvalidCastException err)
{
Console.WriteLine("Нельзя преобразовать тип Circle к типу ITop");
Console.WriteLine(err.Message);
}
//Выполнить!
· Получение интерфейсной ссылки с помощью ключевого слова as (как).
Если объект можно интерпретировать как указанный интерфейс (класс, реализующий интерфейс), то будет возвращена ссылка (адрес) на интерфейс, в противном случае будет возвращена null-ссылка.
//В Main():
Triangle Tr = new Triangle(9);
ITop pr2 = Tr as ITop;
if (pr2 != null)
Console.WriteLine("У треугольника "+pr2.GetTops()+" вершин!");
else
Console.WriteLine("У этой фигуры нет вершин!");
//Выполнить!
· Проверка реализации интерфейса с помощью ключевого слова is (является ли).
Если объект (класс) не совместим с указаным интерфейсом (не реализован интерфейс), то возвращается значение false.
//В Main():
for (int i = 0; i < mas.Length; i++)
{
mas[i].Show();
if (mas[i] is ITop)//Является ли интерфейсным?
Console.WriteLine("У фигуры с номером " + i + " вершин" + (ITop)mas[i]).GetTops());
else
Console.WriteLine("У фигуры с номером " + i + " вершин нет!");
}
Поскольку интерфейсы являются полноценными типами .NET, то в классах можно создавать методы, использующие в качестве параметров интерфейсы, а также возвращающие интерфейсы. Один интерфейс может быть унаследован от другого:
interface B:A
{
//Интерфейсы (заголовки) методов, свойств.
}
Если класс реализует такое наследование, то он должен реализовать все члены и интерфейса А, и интерфейса B.