Дж. Рамбо, М. Блаха - UML 2.0 - Объектно-ориентированное моделирование и разработка (1158633), страница 22
Текст из файла (страница 22)
4.6.1. 8иды множественного наследования Чаще всего множественное наследование используется для наследования от множества несовместных классов. Каждый подкласс является потомком одного класса нз каждого множества. На рис. 4.15 Ги11ТЬлеГпс(!оп!па!СопспЬи1от является одновременно Ги1!Т1теЕтр1оуее и Тлйпг(иа!СолгпЬигог и сочетает в себе их составляющие.
Классы ГиНТ!теЕтр1оуее и РапТплеЕтр1оуее являются несовместными, то есть каждый сотрудник принадлежит ровно одному из них. Классы Мапаяег и Тпп!оЫиа1СолспЬи1ог тоже являются несовместными. Мы могли бы определить три дополнительных класса: Ри11ТплеМапаяег, РапТЬле1ийок1иа!СолгпЬигог и РапТ~теМападег.
Допустимые комбинации зависят от приложения. Каждое обобщение должно производиться по одному аспекту. Множественное наследование можно использовать в том случае, если класс можно уточнить по нескольким независимым аспектам. На рис. 4.15 класс Етр!оуее уточняется по занятости и участию в управлении.
Поэтому модель содержит два набора обобщений. 4 За» 699 88 Глава 4 ° Углубленное моделирование классов Подкласс наследует составляющие от каждого суперкласса только один раз, даже если к нему ведут несколько путей по графу обобщений. Например, на рис. 4.15 Ри!!Т!те!пгйпг!иа1СоптпЬитог наследует составляюшие Етр1оуее по двум путям: через етр!оутепгмагиз и тапаяепа!5гагия.
Однако каждый риПТ!те1пг!!оЫиа!СопитЬигог будет иметь только одну копию составляющих Етр1оуее. Рис. 4.15. Множественное наследование от несовместных классов Конфликты между параллельными определениями создают двусмысленности, которые должны разрешаться на уровне реализации. На практике следует избегать подобных двусмысленностей в моделях или разрешать их явным образом, даже если в используемом языке программирования имеются правила разрешения конфликтов.
Предположим, к примеру, что в классах Ри!!Т~теЕтр!оуее и 1пг1!пЫиа1- СопгпЬигог определен атрибут пате. При этом ЕиПТ(теЕтр!оуее.пате может подразумевать полное имя сотрудника, а 1пг!!вЫиа!Соп!г!Ьигог.пате — его титул или звание. Очевидного способа разрешения такого конфликта не существует. Лучше всего переименовать атрибуты, например, так: ЕиППтеЕтр!оуее.регзопЬ!ате и 1пг1!и!г1иа!СопгпЬигог.Ы!е. (очелерр!яв Рис. 4.16. Множественное наследование от перекрывающихся классов Множественное наследование может иметь место с перекрывающимися классами.
На рис. 4.16 АтрЬ!Ь!оизУеЬ!с!е (Амфибия) является одновременно ЕапИУеЬ!с!е (НаземноеТранспортноеСредство) и )УагетУеЬ!с!е (НадводноеТранспортноеСредство). Классы ЕаЫУеЬ!с!е и ЮагегУеЬ!с1е перекрываются, поскольку некоторые транспортные средства могут перемещаться как по земле, так и по воде.
Для обозначения перекрывающихся наборов обобщений в 11М1. используются ограничения (см. раздел 4.9). Для обозначения используется пунктирная линия, которая проводится поперек перекрывающихся обобщений. Около линии ставятся ключевые слова в фигурных скобках. В нашем примере ключевое слово опег!арр!пя 4.6. Множественное наследование 99 означает, что транспортное средство может принадлежать одновременно к нескольким подклассам. Ключевое слово 1лсотр1еге означает, что на диаграмме не перечислены все возможные подклассы класса $'еЬ|с1е. 4.6.2.
Множественная классификация Экземпляр класса неявным образом является экземпляром всех предков этого класса. Например„преподаватель может одновременно принадлежать к профессорско-преподавательскому составу и к учащимся. Но может ли профессор Гарвардского университета слушать лекции в Массачусетсском технологическом институте? Такая комбинация не описывается никаким классом (если бы он существовал, это было бы крайне искусственное построение).
Это пример множественного наследования, при котором один экземпляр относится к двум перекрывающимся классам. Язык ПМ1. допускает множественную классификацию, но большинство объектно-ориентированных языков поддерживают ее довольно плохо. При использовании традиционных языков лучше всего работать с Регзоп как с объектом, состоящим из множества объектов Пл|оегЫуМетбег (Членуниверситета) (рис. 4.17). Такой обходной маневр заменяет наследование делегированием (о котором речь пойдет в следующем разделе). Правда, при этом теряется индивидуальность отдельных ролей, однако альтернативные подходы потребовали бы радикальных изменений во многих языках программирования 1МсА11езгег-861.
1пв$гисФог Рис. 4,17. Множественная классификация не поддерживается большинством языков 4.6.3. Обходные маневры Проблемы с поддержкой множественного наследования должны были бы решаться на этапе реализации, но чаще всего самым простым решением оказывается реструктурирование модели на ранних этапах проектирования.
В этом разделе мы рассмотрим некоторые приемы реструктурирования. Два подхода используют концепцию делегирования (Йе!ейаг1оп) — механизма реализации, при помощи которого объект передает операцию другому объекту для ее выполнения. Более подробное описание делегирования продолжается в главе 15. ° Делегирование с использованием композиции частей. Суперкласс с несколькими независимыми обобщениями можно переформулировать в виде композиции, в которой обобщение будет заменяться составляющими частями. Этот подход аналогичен описанному в предыдущем разделе для множественной классификации.
Один объект с уникальным идентификатором 100 Глава 4 ° Углубленное моделирование классов заменяется группой связанных объектов, образующих композицию (составной объект). Наследование операций не является автоматическим. Составной объект должен «перехватывать» операции и направлять их соответствующим частям. Например, на рис. 4.18 Етр1оуееЕтр!оутепг (ЗанятостьСлужащего) становится суперклассом Еи!!Т!теЕтр1оуее (СлужащийНаПолнойЗанятости) и РаггТ!теЕтр1оуее (СлужащийНаНеполнойЗанятости). Класс Етр1оуееМапаяетепг (УчастиеСлужащегоВУправлении) становится суперклассом Мапайег (Управляющий) и 1пгйпг!иа1Сопгг!Ьигог (Сотрудник).
Тогда Етр(оуее (Служащий) может быть представлен в виде композиции Етр!оуееЕтр!оутепг и Етр!оуееМапайетепд Операция, вызванная у объекта Етр!оуее, должна быть перенаправлена одной из его частей (Етр1оуееЕтр(оутепс или Етр!оуееМапайетепГ). В этом подходе вам не придется создавать различные комбинации (типа Ри11Т!те!пг!!папа!Сопгпбигог) в виде отдельных классов. Допустимы любые комбинации подклассов различных обобщений.
° Наследование наиболее важных классов с делегированием остальных. В диаграмме классов на рис. 4.19 сохранены индивидуальность и наследование для наиболее важных обобщений. Остальные обобщения низведены до композиции, а их операции делегированы, как в предыдущем варианте. Рис. 4.$8.
Делегирование Рис. 4.19. Наследование и делегирование ° Вложенное обобщение. Сначала система факторизуется по первому обобщению, затем по второму. При этом перебираются все возможные комбинации. Например, на рис. 4.20 мы добавили по два подкласса для управляющих и сотрудников в классы Ри1!Т!теЕтр!оуее и Рагг~теЕтр1оуее. При этом сохраняется наследование, но зато удваивается количество объявлений (и кода) и не сохраняется дух объектно-ориентированного программирования. 4.7. Метаданные 101 Етр/оуев Рис.
4.20. Замена множественного наследования на вложенные обобщения Любой обходной маневр пригоден для облегчения реализации, но все они ухудшают логическую структуру и затрудняют поддержку программ. При выборе подходящего обходного маневра следует руководствоваться несколькими принципами. ° Суперклассы одинаковой важности. Если подкласс имеет несколько суперклассов и все они одинаково важны, лучше всего воспользоваться делегированием (см.
рис. 4.18) и сохранить симметрию модели. ° Доминирующий суперкласс. Если один суперкласс очевидно является наиболее важным, а остальные — менее важны, нужно сохранить наследование от этого суперкласса (см. рис. 4.19 или 4.20). ° Несколько подклассов. Если количество комбинаций невелико, можно воспользоваться вложенным обобщением (см.
рис. 4.20). В противном случае от него следует отказаться. ° Упорядочение наборов обобщений. Если вы использовали вложенное обобщение (см. рис. 4.20), сначала следует обобгцать по наиболее важному критерию, затем — по остальным. ° Большие объемы кода. Следует избегать вложенных обобщений (см.
рис. 4.20), если для их реализации придется дублировать большие объемы кода. ° Индивидуальность. Учитывайте важность сохранения индивидуальности. Это обеспечивается только вложенным обобщением (см. рис. 4.20). 4.7. Метаданные Метэданные (шегадага) — это данные о данных. Хорошим примером метаданных является определение класса. Модели по определению являются метаданными, потому что они описывают моделируемые объекты (а не являются ими). Мета- данные используются во многих применяемых на практике приложениях; это каталоги деталей, светокопии н словари. Столь же широко используются метаданные в реализациях компьютерных языков.
На рис. 4.21 приведен пример, позволяющий сравнить концепции данных и метаданных. Модель автомобиля характеризуется названием, годом, базовой ценой и производителем. В качестве примеров моделей автомобилей можно привести 102 Глава 4 ° Углубленное моделирование классов Роп1 Мцзтапй 1969 года и ч'о)кзюайеп КаЬЬ11 1975 года. Автомобиль как физическая сущность характеризуется серийным номером, цветом, комплектацией и владельцем. В качестве примера можно привести голубой Рогб с серийным номером 1РАВР и красный ч'о1кячайеп с серийным номером 7Е81Р, принадлежащие Джону До. Модель автомобиля описывает множество автомобилей и содержит общие для них всех данные. Модель автомобиля является метаданными по отношению к реальному автомобилю (который в нашем примере представляет собственно данные).
Рис. 4.21. Метаданные и данные Вы можете рассматривать классы как объекты, но на самом деле они являются метаобъектами, а не реальными объектами. Объекты дескрипторов классов обладают составляющими, а те, в свою очередь, характеризуются собственными классами, которые называются метаклассами. Если же рассматривать все сущности как объекты, реализация оказывается более единообразной, и функциональные возможности для решения сложных проблем при таком подходе возрастают.
В разных языках доступность метаданных оказывается различной. В некоторых языках, например акр и Бша!11а1К метаданные могут считываться и изменяться программами во время их выполнения. В других языках, например С++ и )ача, метаданные обрабатываются во время компиляции, а во время выполнения они не доступны (по крайней мере, явным образом). 4.8. Воплощение Воплощение (ге1йсаг1оп) — это превращение в объект чего-либо не являющегося таковым. Воплощение полезно для работы с метаприложениями, потому что оно позволяет сместить уровень абстрагирования. Иногда оно полезно для превращения атрибутов, методов, ограничений и управляющей информации в объекты, чтобы иметь возможность описывать их и манипулировать ими, как данными.
В качестве примера воплощения рассмотрим администратора базы данных. Разработчик может написать код для каждого приложения, чтобы оно могло читать файлы и записывать их. Однако для многих приложений лучше воплотить идею службы данных в виде администратора базы данных. Администратор обладает абстрактной функциональностью, которая дает универсальное решение, позволяющее множеству пользователей надежно и быстро обращаться к данным. В качестве второго примера рассмотрим диаграммы состояний и переходов (о них речь пойдет в следующих двух главах).