Скачиваний:
26
Добавлен:
26.03.2016
Размер:
46.26 Кб
Скачать

Операційні системи і системне програмування

Інтерфейси

Інтерфейс - дослівно "з’єднання". У нашому випадку це деяка програма, що забезпечує взаємодію між іншими програмами або їх частинами. У рамках мови С# інтерфейси - це якісь абстрактні члени, об'єднані під одним ім'ям. Це як би абстрактні класи, але вужчі. Абстрактні класи, окрім абстрактних членів містять ще конструктори, поля даних, неабстрактні члени (члени з реалізацією). Інтерфейси містять тільки абстрактні члени.

Для чого їх ввели в мову? Річ у тому, що абстрактні класи дозволяють налаштовувати свої члени тільки в класах-спадкоємцях (нащадках). Якщо ж у вас в проекті є безліч незв'язаних класових ієрархій, а вам треба, щоб в цих ієрархіях було б звернення до

одного і того ж методу, який щось там робить (в даному випадку кажуть: треба, щоб в ієрархіях підтримувався один і той же поліморфний інтерфейс), то доводиться налаштовуватися в кожній з таких ієрархій на метод (на абстрактний метод), який знаходиться в програмній сутності під назвою "інтерфейс". Ваш даний конкретний клас підключається як би до цього інтерфейсу (за синтаксисом це відбувається як і при спадкуванні: через двокрапку, тільки замість класу батька пишеться конкретний інтерфейс, з якого буде запозичений потрібний метод). Причому в C# не допускається множинне спадкування, тобто побудова класу на основі декількох класів, щоб отримати з них потрібні члени, а "спадкування" від декількох інтерфейсів допускається. Отже, інтерфейс - це заголовки якихось абстрактних методів, об'єднаних під одним ім'ям - іменем інтерфейсу. Наприклад, якийсь інтерфейс IFILE може містити методи FileOpen(), FileClose() та ін.

Ось ще що: коли ви будуєте спадкоємців від базового класу і в батькові є деякі методи М1(), М2(), М3(), ви зобов'язані всі три методи визначити в кожному спадкоємцеві. А якщо вам не потрібні всі методи, а тільки один, наприклад М2() у деякому спадкоємцеві Inh? У цьому випадку виручає інтерфейс. Ви визначаєте інтерфейс з абстрактним членом М2(), вставляєте його в Inh - і все. Решти спадкоємців не чіпаєте.

В інтерфейсі задаються тільки заголовки методів, реалізація методів лягає на клас, який цей інтерфейс підключатиме. Наприклад, клас Triangles (трикутники) походить від класу Shapes (фігури). До класу Triangles додається інтерфейс IPointy, який підраховує число вершин фігури. Тоді в класі Triangles цей інтерфейс повинен бути визначений остаточно:

Class Triangles : Shapes, IPointy

{

// Поля класу

// Конструктори класу

// Властивості класу

// Методи класу

public override void Draw();

// Реалізація в класі інтерфейсу ipointy:

public byte Points // Реалізація у вигляді властивості

{

get { return 3; } // Повертає число вершин трикутника

}

} // Кінець класу

Якщо взяти клас Hexagon (шестикутники) і змусити його підтримувати інтерфейс IPointy, то отримаємо вид класу Hexagon:

Class Hexagon : Shapes, IPointy

{

// Поля класу

// Конструктори класу

// Властивості класу

// Методи класу

public override void Draw();

// Реалізація в класі інтерфейсу ipointy:

public byte Points // Реалізація у вигляді властивості

{

get { return 6; } // Повертає число вершин багатокутника

}

} // Кінець класу

І виклик інтерфейсу йде як виклик звичайного члена з об'єктf.

Hexagon hex = new Hexagon();

int i = hex.Points;

На відміну від класів допускається створення одного інтерфейсу із багатьох (множинне спадкування).

Приклад створення і використання інтерфейсу показаний в програмі представленій лістингом 10.1.

Лістинг 10.1

using System;

namespace app37_interface

{

interface IPrice

{

double Price();

}

interface ICar

{

int Speed { get; set; }

void GetInfo();

}

public class Ferrari : ICar, IPrice

{

private int spd; // швидкість (поле)

public int Speed // швидкість (властивість)

{

get { return spd; }

set { spd = value; }

}

// Конкретна реалізація інтерфейсу в класі:

public void GetInfo()

{

Speed=250;

Console.WriteLine("Це суперкар Ferrari" + "з макс. швидкістю {0}", Speed);

}

// Конкретна реалізація інтерфейсу в класі:

public double Price()

{

return 0; // Console.WriteLine("\nціна автомобіля 20000");

}

}

class Program

{

public static void Main()

{

Console.WriteLine("Створення і застосування " + "інтерфейсу");

Ferrari fr = new Ferrari();

fr.GetInfo();

Console.Write("Press any key to continue...");

Console.ReadKey(true);

}

}

}

У програмі оголошений інтерфейс ICar з однією властивістю Speed (швидкість автомобіля) та одним методом GetInfo(). Що робить цей метод треба конкретно визначити в класі, який почне підключати даний метод. Далі створений клас Ferrari (марка автомобіля), і в класі визначені поле spd (швидкість) і до нього властивість Speed. Потім у клас додана конкретна реалізація абстрактного методу інтерфейсу Icar: встановлена максимальна швидкість автомобіля і видана про це інформація. Результат роботи програми показаний на рис. 10.1.

Рис. 10.1. Робота класу з інтерфейсом

До класу можна підключати скільки завгодно інтерфейсів (через кому). Приклад показаний в лістингу 10.2: доданий ще один інтерфейс який повинен вказати вартість автомобіля.

Лістинг 10.2

using System;

namespace app37_interface2

{

public interface IPrice

{

double Price();

}

public interface ICar

{

int Speed { get; set; }

void GetInfo();

}

public class Ferrari : ICar, IPrice

{

private int spd; // швидкість (поле)

public int Speed // швидкість (властивість)

{

get { return spd; }

set { spd = value; }

}

// Конкретна реалізація інтерфейсу в класі:

public void GetInfo()

{

Speed = 250;

Console.WriteLine("Це суперкар Ferrari " + "з макс. швидкістю {0}", Speed);

}

// Конкретна реалізація інтерфейсу в класі:

public double Price()

{

return 20000;

}

}

class Program

{

public static void Main()

{

Console.WriteLine("Під’єднання до класу більше " + "одного інтерфейсу");

Ferrari fr = new Ferrari();

fr.GetInfo();

Console.WriteLine("Ціна автомобіля - {0}", fr.Price());

Console.Write("Press any key to continue...");

Console.ReadKey(true);

}

}

}

Результат програми представлений на рис. 10.2.

Рис. 10.2. Підключення двох інтерфейсів до класу

Може трапитися так, що в різних інтерфейсах знаходиться один і той же метод (заголовок один і той же). Як цей метод реалізувати в класі, яких їх під’єднує? Адже коли створювалися інтерфейси (і, можливо, різними розробниками), очевидно, що у них передбачалася різна функціональність. Тобто треба досягти того, щоб для одного інтерфейсу в класі метод реалізовував одну функціональність, а для методу з тим же заголовком - іншу функціональність. Очевидно реалізація повинна бути з додаванням префікса до імені інтерфейсу з крапкою до імені методу. Наприклад, для методу price() у різних інтерфейсах треба було б писати при його реалізації в класі: double interf1.price() { реалізація}, а для цього ж методу в іншому інтерфейсі - double interf2.price() {реалізація}.

Інтерфейси можна спадкувати. У них допускається множинне спадкування (один інтерфейс може успадковувати від багатьох). Синтаксис спадкування - такий же, як у класів, а перелік батьків, від яких реалізується спадкоємство, розділяється комами.

5