
- •Тема 5.2. Теоретические основы объектно-ориентированного программирования
- •5.2.1. Основные определения
- •5.2.2. Объектно-ориентированная декомпозиция и объектно-ориентированные модели
- •5.2.3. Объектная модель и ее составные части
- •5.2.4. Средства uml для моделирования классов и их отношений
- •5.2.4.1. Введение в uml
- •5.2.4.2. Статическое представление системы в диаграммах классов
- •5.2.4.3. Визуализация класса
- •5.2.4.4. Уровни представления
- •5.2.4.5. Идентификация классов
- •5.2.4.6. Отношения
- •5.2.4.7. Наследование и обобщение
- •5.2.4.7. Абстрактные классы
- •5.2.4.8. Агрегация и композиция
- •5.2.4.9. Ассоциации
- •5.2.4.10. Классы ассоциаций
- •5.2.4.11 Кратность
- •5.2.4.13. Интерфейс и реализация
- •5.2.4.14. Области видимости
- •5.2.4.15. Зависимости
- •5.2.5. Визуализация существующего кода.
- •Практическое руководство. Поиск кода с помощью обозревателя архитектуры
- •Открытие обозревателя архитектуры
- •Обозреватель архитектуры: домены, представления, узлы, типы узлов и типы ссылок
- •Поиск исходного кода в решении Visual Studio
- •Представление классов в обозревателе архитектуры
- •Поиск кода в решении
- •Поиск скомпилированного кода
- •5.2.6. Visual Studio 2010 - uml моделирования проектов
5.2.4.6. Отношения
Отношения между классификаторами включают в себя ассоциацию, обобщение, реализацию и различные виды зависимостей, в том числе поток и использование (табл. 5.2-1).
Таблица 5.2-1. Виды отношений
-
Отношение
Функция
Ассоциация (Association)
Описание связей между экземплярами классов
Зависимость (Dependency)
Отношение, существующее между двумя элементами модели
Поток (Flow)
Отношение между двумя версиями одного и того же объекта, существующими в последовательные моменты времени
Обобщение (Generalization)
Отношение между общим описанием и более специфическими его разновидностями; используется при наследовании
Реализация (Realization)
Отношение между спецификацией и ее реализацией
Ситуация, когда для корректной работы одному элементу системы необходим другой элемент
5.2.4.7. Наследование и обобщение
Отношение обобщения связывает классификаторы-предки (суперклассы) с их более специализированными потомками (подклассами). С помощью обобщения можно упростить описание классификатора, «собирая» его из отдельных частей, каждая из которых добавляет к классификатору черты, унаследованные от предков. Полное описание классификатора строится с помощью механизма наследования, который основан на обобщении. Обобщение и наследование позволяют указывать, какие общие черты имеет группа классификаторов, не повторяя их в каждом конкретном описании.
Одним из признаков объектно-ориентированного подхода является выполнение одного из общеизвестных аспектов повседневной жизни: если вы знаете что-либо о некоторой категории, то автоматически можете перенести эти знания на другие категории. Если известно, что объект относится к бытовой технике, то уже известно, что он имеет выключатель, имя производителя и номер изделия. Если известно, что объект является животным, то заранее ясно, что оно ест, спит, рождается, перемещается в пространстве, При более детальном анализе можно составить список других атрибутов и операций.
В рамках объектно-ориентированного подхода такое положение вещей называется наследованием. В UML для наследования используется термин обобщение. Один класс (дочерний или подкласс) может наследовать атрибуты и операции другого (родительского класса или суперкласса). Родительский класс является более общим по отношению к дочернему.
Иерархия наследования не ограничивается двумя уровнями: дочерний класс может выступать в роли родительского класса для другого дочернего класса. Класс Млекопитающее является дочерним классом для класса Животное и родительским для класса Лошадь.
В UML наследование отображается с помощью линии, которая соединяет родительский класс с дочерним классом. Конец линии, связанный с родительским классом, помечается не закрашенным треугольником, указывающим на родительский класс. Такая связь соответствует отношению, является видом. Млекопитающее является видом животного, лошадь является видом млекопитающего. На рис. 5.2-19 представлена описанная иерархия наследования и дополнительные классы. На графическом представлении ситуации, когда родительский класс имеет несколько дочерних несколько стрелок-обобщений можно объединить в одно дерево, так что стрелка будет указывать на прямого предка, а несколько ветвей – на прямых потомков, такая конструкция позволяет разгрузить диаграмму. Нужно отметить, что UML не запрещает изображать все без исключения линии и треугольники и не требует указывать наследуемые атрибуты и операции в прямоугольниках подклассов, т.к. они уже представлены в обозначении суперкласса.
Рис. 5.2-19. Иерархия наследования в животном мире.
При моделировании наследования нужно убедиться, что дочерний класс удовлетворяет требованию «является видом» по отношению к родительскому классу. Если связь классов описывается по-другому, нужно использовать другую ассоциацию.
Дочерний класс часто отличается наличием дополнительных атрибутов и операций. Например, Млекопитающее имеет шерсть и дает молоко, а такого атрибута и операции нет в классе Животное.
Класс может не иметь родителя. В этом случае он называется базовым или корневым классом. Класс также может не иметь дочернего класса, и тогда он называется листовым классом. Если класс имеет только одного родителя, то говорят об одиночном наследовании, а если несколько – о множественном.
Обобщение (generalization) – это таксономический вид отношений между общим описанием и специфическим описанием, которое основывается на общем и детализирует его. Специфическое описание полностью согласуется с общим (оно имеет те же свойства, члены и отношения), но обладает также и некоторой дополнительной информацией (млекопитающее имеет шерсть и дает молоко). Общее описание называется прямым предком (parent). Детализированный его вариант называется прямым потомком (child). В нашем примере Животное – это класс – прямой предок, а Млекопитающее – класс – прямой потомок. В применении к классам для прямого предка и прямого потомка существуют другие названия: суперкласс и подкласс.
Обобщение служит для двух целей. Во-первых, чтобы определять условия, при которых экземпляр какого-либо класса (или другого элемента) можно использовать там, где переменная (например, переменная или параметр процедуры) принимает значение этого класса – это называется принципом подстановочности. Правило, следующее из этого принципа, гласит, что экземпляр потомка можно всегда подставить на то место, где объявлено использование предка. Таким образом, объект Млекопитающее подойдет везде, где нужно использовать объект Животное.
Обобщение делает возможными полиморфные операции. Полиморфная операция – это операция, чью реализацию (метод) определяет класс объекта, к которому он принадлежит, а не тот класс, который используется в вызове операции. Это становится возможным, поскольку класс-предок может иметь много прямых потомков, каждый из которых будет реализовывать свои собственные варианты операции, предписанной всем этим классам.
Например, вычисление процентной ставки для ипотеки и для автомобильного лизинга будет разным, однако и в том и в другом случае это будут варианты вычисления процентной ставки общего родительского класса Ссуда (рис. 5.2-20).
^- Обобщение
Рис. 5.2-20. Использование абстрактной операции суперкласса
Любой объект класса-потомка будет подходить там, где объявлено использование класса-предка, причем каждый класс-потомок может обладать при этом своими специфическими операциями. Особенно удобен механизм обобщения при добавлении в существующую модель новых классов, так как при этом не нужно менять полиморфные вызовы. Таким образом, мы можем добавить в систему новый вид займа, не меняя при этом операцию вычисления процентной ставки. Когда полиморфная операция реализована не в классе-предке, а только в классах-потомках, она называется абстрактной.
Еще одной целью обобщения является дать возможность разработчику описывать элемент с помощью черт предков этого элемента. Это называется наследованием. Механизм наследования позволяет «собрать» описание объектов класса из фрагментов описания этого класса и всех описаний его предков. Благодаря наследованию можно один раз дать описание класса, а затем наследовать его всеми классами-потомками, вместо того чтобы повторять это описание в каждом из них. Наследование позволяет существенно уменьшить размер модели и, что более важно, снижает риск случайных несоответствий в программе после внесенных в модель изменений.
Каждый из обобщаемых элементов обладает рядом наследуемых свойств. У многих элементов в число этих свойств входят ограничения. У классификаторов к наследуемым свойствам относятся также атрибуты, операции, принимаемые сигналы и участие в ассоциациях. Элемент-потомок наследует все эти свойства от своих предков. Полный набор его свойств будет включать в себя не только унаследованные, но и индивидуальные черты.
У классификаторов не может быть более одного атрибута с одной и той же сигнатурой (вне зависимости от того, наследованный это атрибут или нет). В противном случае возникает конфликтная ситуация и модель считается плохо согласованной. Другими словами, у потомка нельзя повторно объявлять тот атрибут, который уже объявлен у предка.
Операцию можно объявлять более чем в одном классификаторе, но при условии, что спецификации операции совместимы (одни и те же параметры, ограничения и возвращаемые значения).
Метод может быть объявлен в нескольких иерархических классах. Причем метод, относящийся непосредственно к потомку, подменяет собой метод с той же сигнатурой, унаследованный от предка. Если же класс наследует две различные копии метода (путем множественного наследования у разных классов), возникает конфликтная ситуация и модель также считается плохо согласованной. Некоторые языки программирования допускают в такой ситуации выбор одного из методов. Однако более простым и надежным способом разрешения такой ситуации будет переопределить метод в классе-потомке.
Ограничения элементов также бывают индивидуальными и унаследованными от предков. Если какие-то из них конфликтуют между собой, модель считается плохо согласованной.
Каждая унаследованная или объявленная операция в конкретном классе должна иметь определенный метод (который может наследоваться от класса-предка).