Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
7 семестр / Учебники / Все лекции С# / Все лекции С# / Лекции C# for print fineprint.docx
Скачиваний:
325
Добавлен:
24.02.2016
Размер:
523.48 Кб
Скачать

Интерфейсы

Интерфейсом называется семейство явно описанных как public - методов и свойств, которые сгруппированы в единое целое и инкапсулируют какую-либо определенную функциональную возможность.

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

В предыдущем примере, касающемся кофе, можно сгруппировать в интерфейс несколько свойств и методов наиболее общего назначения, например, AddSugar(), Milk (молоко), Sugar (сахар) и Instant (растворимый). Такой интерфейс можно назвать как-нибудь вроде IHotDrink (горячий напиток) - (имена интерфейсов обычно предваряются заглавной буквой i). Этот интерфейс допустимо использовать и для каких-нибудь других объектов, возможно, принадлежащих к классу CupOfTea (чашка чая). Другими словами, получается возможность обращаться с этими объектами одинаковым образом, а они при этом по-прежнему могут обладать своими собственными индивидуальными свойствами (например, сорт кофейных бобов (Marka) для класса CupOfCoffee и сорт чайного листа (MarkaTea) для класса CupOfTea).

Интерфейсы, реализованные на объектах UML, изображаются с помощью "леденцового" синтаксиса. На диаграмме, приведенной на рисунке 13.5 слева, члены IHotDrink выделены в отдельный прямоугольник с помощью синтаксиса, напоминающего используемый для описания классов.

CupOfCoffee

+Marka: string


<<Interface>>

IHotDrink

+Instant: bool

+Milk: bool

+Sugar: bool

-Description: string

+AddSugar(in amount: byte): byte

IHotDrink

CupOfTea

+MarkaTea: string


IHotDrink

Рисунок 13.5 – UML-представление интерфейсов

У класса может быть несколько интерфейсов, и несколько классов могут поддерживать один и тот же интерфейс. Понятие интерфейса позволяет, таким образом, облегчить жизнь другим разработчикам и пользователям. Допустим, что у вас имеется некий код, в котором задействован объект, обладающий определенным интерфейсом. Если предположить, что вы не используете другие свойства и методы данного объекта, то появляется возможность заменять один объект на другой(код, в котором используется интерфейс IHotDrink, может работать как с экземпляром класса CupOfCoffee, так и с экземпляром класса CupOfTea). Кроме того, разработчик самого объекта имеет возможность снабжать вас усовершенствованными версиями этого объекта — если он поддерживает использовавшийся ранее интерфейс, то не составит никакого труда применить новую версию объекта в вашей программе.

Основные свойства ооп

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

1. Инкапсуляция – способность прятать детали реализации объектов от пользователей этих объектов. Например, предположим, что создан класс с именем DBReader (для работы с базой данных), в котором определено два главных метода: Ореn() и Close(). Класс DBReader скрывает за счет инкапсуляции подробности открытия и закрытия баз данных.

DBReader f = new DBReader();

f.Open(@"C:\foo.mdf ");

//Выполнение с базой данных необходимых действий

f.Close();

Класс DBReader инкапсулирует внутренние подробности того, как именно он обнаруживает, загружает, выполняет операции и закрывает файл базы данных.

За счет инкапсуляции программирование становится проще: нет необходимости беспокоиться об огромном количестве строк кода, которые выполняют свою задачу скрыто от разработчика. Все, что требуется от программиста — создать экземпляр нужного класса и передать ему необходимые сообщения (типа “открыть файл с именем foo.mdf”).

С философией инкапсуляции тесно связан еще один принцип — сокрытия всех внутренних данных (то есть переменных-членов) класса. Все внутренние переменные члены класса должны быть определены как private. В результате обращение к ним из внешнего мира будет возможно только при помощи открытых функций — членов. Такое решение, помимо всего прочего, защищает программиста от возможных ошибок, поскольку открытые данные очень просто повредить.

2. Наследование является одной из наиболее важных особенностей ООП. Любой класс может наследоваться от другого класса, что означает, что он будет обладать всеми членами того класса, от которого он наследуется. В терминологии ООП класс, от которого происходит наследование, называется базовым классом, класс, который наследуется, называется производным классом. В С# все объекты происходят от единственного базового класса. Наследование позволяет расширять или создавать более специфические классы на основе одного базового класса System.Object.

Например, представьте себе класс, описывающий домашнее животное. Этот класс можно назвать Animal (животное) и включить в него такой метод, как EatFood() (принимать пищу). После этого можно создать производный класс с именем Cow (корова), который будет поддерживать метод EatFood(), но при этом может обладать и своими собственными, например, Mоо() (мычать) и SupplyMilk() (давать молоко). Можно создавать и другие производные классы, например, класс Chicken (курица) с методами Cluck() (кудахтать) и LayEgg() (нести яйца).

В UML наследование изображается с помощью стрелок (рисунок 13.6). Здесь для краткости опущены члены, обладающие возвращаемыми значениями.

Animal

+EatFood()


Chicken

+ Cluck()

+LayEgg()

Cow

+ Moo()

+SupplyMilk()


Рисунок 13.6 – UML-представление наследования

При наследовании от одного базового класса возникает очень важный вопрос о режиме доступа к членам данного класса. Частные члены базового класса, в отличие от общих членов, доступны не будут. Однако общие члены будут доступны как производному классу, таки внешнему коду. Это означает, что при использовании только этих двух режимов доступа мы не можем получить член, который был бы доступен базовому классу и производному классу, но не был бы при этом доступен для внешнего кода. Для решения этой проблемы вводится третий режим доступа — protected (защищенный), при котором доступ открыт только для производных классов.