ЯЗЫК ПРОГРАММИРОВАНИЯ С# 2005 И ПЛАТФОРМА .NET 2.0. 3-е издание
Шрифт:
• Полиморфизм. Как данный язык позволяет интерпретировать родственные объекты унифицированным образом?
Перед тем как начать рассмотрение синтаксических особенностей реализации каждого из этих принципов, важно понять базовую роль каждого из них. Поэтому здесь предлагается краткая теоретическая информация по соответствующим вопросам, просто для того, чтобы исключить разночтения, которые могут возникать у людей, ощущающих постоянную нехватку времени на теорию из-за жестких сроков окончания их проектов.
Инкапсуляция
Первым принципом ООП является инкапсуляция. По сути, она означает возможность скрыть средствами языка несущественные детали реализации от
Вымышленный класс DatabaseReader инкапсулирует внутренние возможности размещения, загрузки, обработки и закрытия файла данных. Пользователи объекта приветствуют инкапсуляцию, поскольку этот принцип ООП позволяет упростить задачи программирования. Нет необходимости беспокоиться о многочисленных строках программного кода, который выполняет работу класса DatabaseReader "за кулисами". Bсe, что требуется от вас, – это создание экземпляра и отправка подходящих сообщений (например, "открыть файл Employees.mdf, размещенный на моем диске C").
Одним из аспектов инкапсуляции является защита данных. В идеале данные состояния объекта должны определяться, как приватные, a не открытые (как было в предыдущих главах). В этом случае "внешний мир" будет вынужден "смиренно просить" право на изменение или чтение соответствующих значений.
Наследование
Следующим принципом ООП является наследование, означающее способность языка обеспечить построение определений новых классов на основе определений существующих классов. В сущности, наследование позволяет расширить возможности поведения базового класса (называемого также родительским классом) с помощью построения подкласса (называемого производным классам или дочерним классом), наследующего функциональные возможности родительского класса. На рис. 4.3 иллюстрируется отношение подчиненности ("is-а") для родительских и дочерних классов.
Рис. 4.3. Отношение подчиненности для родительских и дочерних классов
Можно прочитать эту диаграмму так: "Шестиугольник (hexagon) является формой (shape), которая является объектом (object)". При создании классов, связанных этой формой наследования, вы создаете отношения подчиненности между типами. Отношение подчиненности часто называется классическим наследованием.
Вспомните из главы 3, что System.Object является предельным базовым классом любой иерархии .NET. Здесь класс Shape (форма) расширяет Object (объект). Можно предположить, что Shape определяет некоторый набор свойств, полей, методов и событий, которые будут общими для всех форм. Класс Hexagon (шестиугольник) расширяет Shape и наследует функциональные возможности, определенные в рамках Shape и Object, вдобавок к определению своих собственных членов (какими бы они ни были).
В мире ООП есть и другая форма многократного использования программного кода - это модель локализации/делегирования (также известная, как отношение локализации, "has-a"). Эта форма многократного использования программного кода не используется дли создания отношений "класс-подкласс". Скорее данный класс может определить член-переменную другого класса и открыть часть или все свои функциональные возможности для "внешнего мира".
Например, если создается модель автомобиля, то вы можете
Здесь тип-контейнер (Car) несет ответственность за создание содержащегося объекта (Radio). Если объект Car "желает" сделать поведение Radio доступным для экземпляра Car, он должен пополнить свой собственный открытый интерфейс некоторым набором функций, Которые будут действовать на содержащийся тип. Заметим, что пользователь объекта не получит никакой информации о том, что класс Car использует внутренний объект Radio.
Полиморфизм
Третьим принципом ООП является полиморфизм. Он характеризует способность языка одинаково интерпретировать родственные объекты. Эта особенность объектно-ориентированного языка позволяет базовому классу определить множество членов (формально называемых полиморфным интерфейсом) для всех производных классов. Полиморфный интерфейс типа класса строится с помощью определения произвольного числа виртуальных, или абстрактных членов. Виртуальный член можно изменить (или, говоря более формально, переопределить) в производном классе, тогда как абстрактный метод должен переопределяться. Когда производные типы переопределяют члены, определенные базовым классом, они, по существу, переопределяют свой ответ на соответствующий запрос.
Чтобы проиллюстрировать понятие полиморфизма, снова используем иерархию форм. Предположим, что класс Shape определил метод Draw, не имеющий параметров и не возвращающий ничего. С учетом того, что визуализация для каждой формы оказывается уникальной, подклассы (такие как Hexagon и Circle) могут переопределить соответствующий метод так, как это требуется для них (рис. 4.4).
Рис. 4.4. Классический полиморфизм
После создания полиморфного интерфейса можно использовать различные предположения, касающиеся программного кода. Например, если Hexagon и Circle являются производными от одного общего родителя (Shape), то некоторый массив типов Shape может содержать любой производный класс. Более того, если Shape определяет полиморфный интерфейс для всех производных типов {в данном примере это метод Draw, то можно предположить, что каждый член в таком массиве имеет эти функциональные возможности. Проанализируйте следующий метод Main, в котором массиву типов, производных от Shape, дается указание визуализировать себя с помощью метода Draw.