Читайте также:
|
|
Когда класс определен как абстрактный базовый (с помощью ключевого слова abstract), в нем может определяться любое количество абстрактных членов. Абстрактные члены могут использоваться везде, где необходимо определить член, которые не предлагает реализации по умолчанию. За счет этого вы навязываете полиморфный интерфейс каждому наследнику, возлагая на них задачу реализации конкретных деталей абстрактных методов. Полиморфный интерфейс абстрактного базового класса просто ссылается на его набор виртуальных и абстрактных методов.
Данная особенность ООП позволяет строить легко расширяемое и гибкое программное обеспечение.
Пример 2.
Для иллюстрации полиморфизма рассмотрим иерархию фигур.
Для начала создадим новое консольное приложение С# по имени ShapeExample.
(этот код вставляем в проект ShapeExample, пространство имен Shapes)
Задание!!!: протестировать, исправить возможные ошибки
Обратите внимание что типы Hexagon и Circle расширяют базовый класс Shape. Подобно любому базовому классу, в Shape определен набор членов (в данном случае свойство PetName и метод Draw()), общих для всех наследников. Подобно иерархии классов сотрудников, нужно запретить непосредственное создание экземпляров Shape, поскольку этот тип представляет слишком абстрактную концепцию. Чтобы предотвратить прямое создание экземпляров Shape, можно определить его как абстрактный класс. Также, учитывая, что производные типы должны уникальным образом реагировать на вызов метода Draw(), пометим его как virtual и определим реализацию по умолчанию.
(этот код вставляем в проект ShapeExample, пространство имен Shapes)
Задание!!!: протестировать, исправить возможные ошибки
Польза от абстрактных методов становится совершенно ясной, как только приходит понимание, что подклассы никогда не обязаны переопределять виртуальные методы (как в случае Circle). Поэтому если создать экземпляр типа Hexagon и Circle, обнаружится, что Hexagon знает, как правильно "рисовать" себя (или, по крайней мере, выводит на консоль соответствующее сообщение). Однако реакция Circle иная:
(этот код вставляем в проект ShapeExample, метод Main)
Задание!!!: протестировать, исправить возможные ошибки
Вывод этого метода Main() выглядит следующим образом:
Ясно, что это не особо интеллектуальный дизайн для текущей иерархии. Чтобы заставить каждый класс переопределить метод Draw(), можно определить Draw() как абстрактный метод класса Shape, а это означает отсутствие какой-либо реализации по умолчанию. Для пометки метода как абстрактного в С# служит ключевое слово abstract, абстрактные методы не предусматривают вообще никакой реализации:
(этот код вставляем в проект ShapeExample, класс Shape)
Задание!!!: протестировать, исправить возможные ошибки
Важно! Абстрактные методы могут определяться только в абстрактных классах. Попытка поступить иначе приводит к ошибке во время компиляции.
Методы, помеченные как abstract, являются чистым протоколом. Они просто определяют имя, возвращаемый тип (если есть) и набор параметров (при необходимости). Здесь абстрактный класс Shape информирует типы-наследники о том, что у него есть метод по имени Draw(), который не принимает аргументов и ничего не возвращает. О необходимых деталях должен позаботиться наследник. С учетом этого метод Draw() в классе Circle теперь должен быть обязательно переопределен. В противном случае Circle также должен быть абстрактным типом и оснащен ключевым словом abstract (это очевидно не подходит в данном примере). Ниже показаны необходимые изменения в коде:
(этот код вставляем в проект ShapeExample, класс Circle)
Задание!!!: протестировать, исправить возможные ошибки
Теперь делается предположение о том, что любой унаследованный от Shape класс должен иметь уникальную версию метода Draw(). Для демонстрации полной картины полиморфизма рассмотрим следующий код:
(этот код вставляем в проект ShapeExample, метод Main)
Задание!!!: протестировать, исправить возможные ошибки
Ниже показан вывод этого метода Main():
Этот метод Main () иллюстрирует использование полиморфизма в чистом виде. Хотя невозможно напрямую создавать экземпляры абстрактного базового класса (Shape), можно свободно сохранять ссылки на объекты любого подкласса в абстрактной базовой переменной. Таким образом, созданный массив объектов Shape может хранить объекты, унаследованные от базового класса Shape (попытка поместить в массив объекты, несовместимые с Shape, приводит к ошибке во время компиляции).
Учитывая, что все элементы в массиве my Shapes действительно наследуются от Shape, известно, что все они поддерживают один и тот же полиморфный интерфейс (или, говоря конкретно — все они имеют метод Draw()). Выполняя итерацию по массиву ссылок Shape, исполняющая система сама определяет, какой конкретный тип имеет каждый его элемент. И в этот момент вызывается корректная версия метода Draw(). Эта техника также делает очень простой и безопасной задачу расширения текущей иерархии. Например, предположим, что от абстрактного базового класса Shape унаследовано еще пять классов (Triangle, Square и т.д.). Благодаря полиморфному интерфейсу, код внутри цикла foreach не потребует никаких изменений, если компилятор увидит, что в массив myShapes помещены только Shape -совместимые типы.
Дата добавления: 2015-07-25; просмотров: 215 | Нарушение авторских прав
<== предыдущая страница | | | следующая страница ==> |
Абстрактные классы | | | Сокрытие методов |