Иерархичность
Абстракция является полезным инструментом. Однако всегда, кроме самых простых ситуаций, число абстракций в системе намного превышает наши умственные возможности. Инкапсуляция позволяет в какой-то степени устранить это препятствие, убрав из поля зрения внутреннее содержание абстракций. Модульность также упрощает задачу, объединяя логически связанные абстракции в группы. Но этого оказывается недостаточно.
Значительное упрощение в понимании сложных задач достигается за счет образования из абстракций иерархической структуры.
Иерархия – ранжированная или упорядоченная система абстракций.
Принцип иерархичности предполагает использование иерархических структур при разработке программных систем.
Основными видами иерархических структур применительно к сложным системам являются иерархии типа «является» и иерархии типа «имеет».
Иерархия «является» подразумевает, что элемент, стоящий на нижнем уровне абстракции, является разновидностью (частным случаем) элемента, стоящего на верхнем уровне.
Например, лазерный принтер является разновидностью принтеров: лазерный принтер является принтером; принтер HP LaserJet 1020 является разновидностью лазерных принтеров: принтер HP LaserJet 1020 является лазерным принтером (рис. 2.2). Понятие «принтер» обобщает свойства, присущие всем принтерам, а лазерный принтер – это просто особый тип принтера со свойствами, которые отличают его, например, от матричного или струйного принтера.
Рис. 2.2. Иерархия «является» для принтеров
Важный элемент объектно-ориентированных систем и основной вид иерархии «является» – иерархия наследования (отношение родитель–потомок).
Наследование означает такое отношение между абстракциями, когда абстракция-потомок заимствует структурную и/или функциональную часть одной или нескольких абстракций-родителей. Если абстракция-потомок заимствует часть одной абстракции-родителя, то говорят об одиночном наследовании. Если же потомок заимствует части нескольких родителей, то говорят о множественном наследовании. Часто потомок достраивает или переписывает компоненты родителя.
«Лакмусовой бумажкой» наследования является обратная проверка. Если В не есть А, то В не стоит производить от А.
В наследственной иерархии общая часть структуры и поведения сосредоточена в наиболее общей абстракции. Потомок представляет собой специализированный частный случай своего предка. По этой причине говорят о наследовании как об иерархии обобщение–специализация. Таким образом, абстракция, стоящая на верхнем уровне, является обобщением для нижестоящей, а нижестоящая – специализацией вышестоящей.
Принцип наследования позволяет упростить выражение абстракций, делает проект менее громоздким и более выразительным. В отсутствие наследования каждая часть сложной системы становится самостоятельным блоком и должна разрабатываться «с нуля». Абстракции лишаются общности, поскольку каждый программист реализует их по-своему. Стройность системы достигается тогда только за счет дисциплинированности программистов.
С другой стороны, принципы абстрагирования, инкапсуляции и иерархичности находятся между собой в некоем здоровом конфликте. Абстрагирование и инкапсуляция создают непрозрачный барьер, скрывающий состояние и функции объекта; принцип наследования требует открыть доступ и к состоянию, и к функциям объекта для производных объектов.
Пример. Одиночное наследование. Вернемся к иерархии «принтер – лазерный принтер» (лазерный принтер является разновидностью принтеров).
Абстракция «лазерный принтер» строится на основе родительской абстракции «принтер». «Лазерный принтер» наследует от «принтера» свойства, определяющие все принтеры. Кроме того, лазерный принтер имеет структурные и функциональные части, реализующие свойства, которые характерны именно для лазерных принтеров.
Пример. Множественное наследование. Введем абстракции «временный работник» и «секретарь». Секретарь может быть постоянным работником или временным. В последнем случае абстракция «временно работающий секретарь» наследует компоненты обеих абстракций. Временно работающий секретарь выполняет обязанности секретаря и имеет правовой статус временного работника.
Множественным наследованием часто злоупотребляют. Например, сладкая вата – это частный случай сладости, но никак не ваты. Следует применять ту же «лакмусовую бумажку»: если В не есть А, то ему не стоит наследовать от А.
Иерархия «имеет» вводит отношение агрегации (целое/часть).В иерархии «имеет» некоторая абстракция находится на более высоком уровне, чем любая из использовавшихся при ее реализации.
Агрегация есть во всех языках, использующих структуры или записи, состоящие из разнотипных данных. Но в объектно-ориентированном программировании она обретает новую мощь: агрегация позволяет физически сгруппировать логически связанные структуры, а наследование с легкостью копирует эти общие группы в различные абстракции.
Пример. Компьютер (рис. 2.3) имеет системный блок (системный блок является частью компьютера). Системный блок компьютера одновременно имеет (агрегирует) материнскую плату, платы оперативной памяти, центральный процессор и множество других компонентов. Заметим, что от замены процессора на более мощный, от добавления нескольких плат оперативной памяти или второго жесткого диска системный блок не становится другим системным блоком. Если же мы разбираем системный блок, мы уничтожаем его как объект, однако его компоненты остаются и могут быть использованы в других системных блоках. Другими словами, системный блок и его компоненты имеют свои отдельные и независимые сроки жизни.
Рис. 2.3. Компьютер: иерархия «имеет»