Интерфейсы

В объектно-ориентированном программировании иногда требуется определить, что класс должен делать, а не как он будет это делать. Вы уже видели такой подход на примере абстрактного метода. Абстрактный метод определяет сигнатуру для метода, но не обеспечивает его реализации. В производном классе каждый абстрактный ме­тод, определенный базовым классом, реализуется по-своему. Таким образом, абст­рактный метод задает интерфейс для метода, но не способ его реализации. Несмотря на всю полезность абстрактных классов и методов, эту идею можно развить. В С# предусмотрена возможность полностью отделить интерфейс класса от его реализации с помощью ключевого слова interface.

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

Для реализации интерфейса класс должен обеспечить тела (способы реализации) методов, описанных в интерфейсе. Каждый класс может определить собственную реа­лизацию. Таким образом, два класса могут реализовать один и тот же интерфейс раз­личными способами, но все классы поддерживают одинаковый набор методов. Следо­вательно, код, "осведомленный" о наличии интерфейса, может использовать объекты любого класса, поскольку интерфейс для всех объектов одинаков. Предоставляя про­граммистам возможность применения такого средства программирования, как интер­фейс, С# позволяет в полной мере использовать аспект полиморфизма, выражаемый как "один интерфейс — много методов".

Интерфейсы объявляются с помощью ключевого слова interface. Вот как выгля­дит упрошенная форма объявления интерфейса:

interface имя{

тип_возврата имя_метода1(список_параметров) ;

тип_возврата имя_метода2(список_параметров);

…………….

тип__возврата имя_методаN(слисок_параметров);

}

Имя интерфейса задается элементом имя. Методы объявляются с использованием лишь типа возвращаемого ими значения и сигнатуры. Все эти методы, по сути, — аб­страктные. Как упоминалось выше, для методов в интерфейсе не предусмотрены спо­собы реализации. Следовательно, каждый класс, который включает интерфейс, дол­жен реализовать все его методы. В интерфейсе методы неявно являются открытыми (public-методами), при этом не разрешается явным образом указывать спецификатор доступа.

Рассмотрим пример интерфейса для класса, который генерирует ряд чисел,

public interface ISeries {

int getNextO; // Возвращает следующее число ряда,

void reset{); // Выполняет перезапуск,

void setStart(int x); // Устанавливает начальное

// значение.

}

Этот интерфейс имеет имя ISeries. Хотя префикс "I" необязателен, многие программисты его используют, чтобы отличать интерфейсы от классов. Интерфейс ISeries объявлен открытым, поэтому он может быть реализован любым классом в любой программе.

Помимо сигнатур методов интерфейсы могут объявлять сигнатуры свойств, индек­саторов и событий. События рассматриваются в главе 15, поэтому здесь мы остано­вимся на методах, индексаторах и свойствах. Интерфейсы не могут иметь членов дан­ных. Они не могут определять конструкторы, деструкторы или операторные методы. Кроме того, ни один член интерфейса не может быть объявлен статическим.