Гради Буч - Объектно-ориентированный анализ и проектирование с примерами приложений на С++ (1158635), страница 43
Текст из файла (страница 43)
Ограничение доступа будет обсуждатьсяниже.Категория может использовать невложенные категории и классы. Сдругой стороны, и классы могут использовать категории. Для единообразиямы обозначаем эти экспортно-импортные отношения так же, как отношениеиспользования между классами (см. рис. 5-4). Например, если категория Aиспользует категорию B, это означает, что классы из A могут бытьнаследниками, или содержать экземпляры, использовать или быть еще как-тоассоциированы с классами из B.Рис.
5-7. Диаграмма классов верхнего уровня для гидропонной системыКогда в категории слишком много общих классов, вроде базовыхклассов-контейнеров или других базовых классов, подобных Object вSmalltalk, возникают практические затруднения. Такие классы будутиспользоваться чуть ли не всеми другими категориями, загромождая корневойуровень диаграммы.
Чтобы выйти из положения, такие категории помечаютсяключевым словом global в левом нижнем углу значка, показывающим, чтокатегория по умолчанию может быть использована всеми остальными.Диаграммы классов верхнего уровня, содержащие только категорииклассов, представляют архитектуру системы в самом общем виде. Такиедиаграммы чрезвычайно полезны для визуализации слоев и разделов системы.Слой обозначает набор категорий классов одного уровня абстракции.
Такимобразом, слои представляют набор категорий классов, так же как категорииклассов - это кластеры классов. Слои обычно нужны, чтобы изолироватьверхние уровни абстракции от нижних. Разделы обозначают связанные(каким-либо образом) категории классов на разных уровнях абстракции. Вэтом смысле слои представляют собой горизонтальные срезы системы, аразделы - вертикальные.Пример.
На рис. 5-7 приведен пример диаграммы классов верхнегоуровня для тепличного хозяйства. Это типичная многослойная система. Здесьабстракции, которые ближе к реальности (а именно активаторы и датчикиклимата и удобрений), располагаются на самых нижних уровнях, аабстракции, отражающие понятия пользователя, - ближе к вершине. Категорияклассов ТипыПосевов - глобальна, то есть ее услуги доступны всем другимкатегориям. На значке категории классов Планирование показаны два ееважных класса: GardeningPlan (план выращивания) с рис. 5-5 иPlanAnalyst (анализатор планов). При увеличении любой из восьмикатегорий классов, показанных на рисунке, обнаружатся составляющие ихклассы.Рис. 5-8.
Значок параметризованного классаДополнительные обозначенияДо сих пор мы занимались существенной частью нашей системыобозначений.5 Однако, чтобы передать некоторые часто встречающиесястратегические и тактические решения, нам потребуется расширить ее. Общееправило: держаться существенных понятий и обозначений, а дополнительныеприменять только тогда, когда они действительно необходимы.Параметризованные классы.
В некоторых объектноориентированных языках программирования, в частности, C++, Eiffel и Adaможно создавать параметризованные классы. Как было сказано в главе 3,параметризованным классом называется семейство классов с общейструктурой и поведением. Чтобы создать конкретный класс этого семейства,нужно подставить вместо формальных параметров фактические (процессинстанцирования). Конкретный класс может порождать экземпляры.Параметризованные классы достаточно сильно отличаются отобычных, что отмечается специальным украшением на их значках.
Какпоказывает пример на рис. 5-8, параметризованный класс изображаетсязначком обычного класса с пунктирным прямоугольником в правом верхнемуглу, в котором указаны параметры. Инстанцированный класс изображаетсяобычным значком класса с украшением в виде прямоугольника (со сплошнойграницей) с перечисленными в нем фактическими параметрами.Связь между параметризованным классом и его инстанцированиемизображается пунктирной линией, указывающей на параметризованный класс.Для получения инстанцированного класса необходим другой конкретныйкласс как фактический параметр (GardeningPlan в этом примере).Параметризованный класс не может порождать экземпляры и не можетиспользоваться сам в качестве параметра. Каждый Инстанцированный классявляется новым классом, отличающимся от других конкретных классов тогоже семейства.5Все существенные элементы в совокупности как раз и образуют нотацию Booch Lite.Метаклассы.
В некоторых языках, таких как Smalltalk и CLOS, естьметаклассы. Метакласс (см. главу 3) - это класс класса. В Smalltalk, например,метаклассы - это механизм поддержки переменных и операций класса(подобных статическим членам класса в C++), особенно фабрик класса(производящих операций), создающихРис. 5-9. Значок метаклассаэкземпляры объектов данного класса. В CLOS метаклассы играют важнуюроль в возможности уточнения семантики языка [9].Метаклассы принципиально отличаются от обычных классов, и, чтобыподчеркнуть это, их значок закрашивается серым цветом, как это сделано нарис.
5-9. Связь между классом и его метаклассом (метасвязь) имеет виджирной стрелки, направленной от класса к его метаклассу. МетаклассGardeningPlan обеспечивает методы-фабрики new() и default (),которые создают новые экземпляры класса GardeningPlan.Метакласс не имеет экземпляров, но может любым образом бытьассоциирован с другими классами.Метасвязь имеет еще одно применение. На некоторых диаграммахклассов бывает полезно указать объект, который является статическим членомнекоторого класса. Чтобы показать класс этого объекта, мы можем провестиметасвязь "объект/ класс". Это согласуется с предыдущим употреблением:связь между некоторой сущностью (объектом или классом) и ее классом.Утилиты классов. Благодаря своему происхождению, гибридныеязыки, такие как C++, Object Pascal и CLOS, позволяют разработчикуприменять как процедурный, так и объектно-ориентированный стильпрограммирования.
Это контрастирует со Smalltalk, который целикоморганизован вокруг классов. В гибридном языке есть возможность описатьфункцию-не-член, называемую также свободной подпрограммой. Свободныеподпрограммы часто возникают во время анализа и проектирования награнице объектно-ориентированной системы и ее процедурного интерфейса свнешним миром.Утилиты классов употребляются одним из двух способов. Во-первых,утилиты класса могут содержать одну или несколько свободных подпрограмм,и тогда следует просто перечислить логические группы таких функций-нечленов.
Во-вторых, утилиты класса могут обозначать класс, имеющий толькопеременные (и операции) класса (в C++ это означало бы класс только состатическими элементами6). Таким классам нет смысла иметь экземпляры,потому что все экземпляры будут находиться в одном и том же состоянии.Такой класс сам выступает в роли своего единственного экземпляра.6Программирующие на Smalltalk часто используют идиому утилит, чтобы достичьтого же эффекта.Рис. 5-10. Значок утилиты классовКак показано на рис. 5-10, утилита классов обозначается обычнымзначком класса с украшением в виде тени. В этом примере утилита классовPlanMetrics (параметры плана) предоставляет две важные операции:expectedYield (ожидаемый урожай) и timeToHarvest (время сбораурожая).
Утилита обеспечивает эти две операции на основе услуг,предоставляемых классами нижнего уровня - GardeningPlan (план) иCropDatabase (база данных об урожае). Как показывает диаграмма,PlanMetrics зависит от CropDatabase: получает от нее информацию обистории посевов. В свою очередь, класс PlanAnalyst использует услугиPlanHetrics.Рис.
5-10 иллюстрирует обычное использование утилит классов: здесьутилита предоставляет услуги, основанные на двух независимых абстракцияхнижнего уровня. Вместо того, чтобы ассоциировать эти операции с классамивысшего уровня, таких как PlanAnalyst, мы решили собрать их в утилитуклассов и добились четкого разделения обязанностей между этими простымипроцедурными средствами и более изощренной абстракцией классаанализатора PlanAnalyst.
Кроме того, включение свободных подпрограмм водну логическую структуру повышает шансы на их повторное использование,обеспечивая более точное разбиение абстракции.Связь классов с утилитой может быть отношением использования, ноне наследования или агрегирования. В свою очередь, утилита класса можетвступать в отношение использования с другими классами и содержать ихстатические экземпляры, но не может от них наследовать.Подобно классам, утилиты могут быть параметризованы иинстанцированы.
Для обозначения параметризованных утилит используютсятакие же украшения, как и для параметризованных классов (см. рис. 5-8).Аналогично, для обозначения связи между параметризованной утилитойкласса и ее конкретизацией мы используем то же обозначение, что и дляинстанцирования параметризованных классов.Вложенность.
Классы могут быть физически вложены в другиеклассы, а категории классов - в другие категории и т. д. Обычно это нужно длятого, чтобы ограничить видимость имен. Вложение соответствует объявлениювложенной сущности в окружающем ее контексте. Мы изображаемвложенность физически вложенным значком; на рис. 5-11 полное имявложенного класса - Nutritionist::NutrientProfile.Рис. 5-11. Значок вложенностиВ соответствии с правилами выбранного языка реализации, классымогут содержать экземпляры вложенного класса или использовать его. Языкиобычно не допускают наследования от вложенного класса.Обычно вложение классов является тактическим решениемпроектировщика, а вложение категорий классов - типично стратегическоеархитектурное решение. В обоих случаях необходимость в использованиивложения на глубину более одного-двух уровней встречается крайне редко.Управление экспортом.
Все основные языки объектноориентированного программирования позволяют четко разделить интерфейскласса и его реализацию. Кроме того, как описано в главе 3, большинство изних позволяет разработчику определить более детально доступ к интерфейсукласса.Например, в C++ элементы класса бывают открытыми (доступны всемклиентам), защищенными (доступны только подклассам, друзьям и самомуклассу) и закрытыми (доступны только самому классу и его друзьям).
Крометого, некоторые элементы могут быть частью реализации класса и тем самымбыть недоступными даже друзьям этого класса.7 В Ada элементы класса могутбыть открытыми или закрытыми. В Smalltalk все переменные экземпляров поумолчанию закрытые, а все операции - открытые. Доступ предоставляетсясамим классом и только явно: клиент ничего не может получить насильно.Мы изображаем способ доступа следующими украшениями связи:•<нет украшения>открытый (по умолчанию)защищенный•|закрытый•||реализация•|||Мы ставим их как "засечки" на линии связи у источника.
Например, нарис. 5-12 показано, что класс GrainCrop множественно наследует от классовCrop (посев) (открытый суперкласс) и FoodItem (пища) (защищенныйсуперкласс).7Например, объект или класс, описанный в .срр-файле, доступен только функциямчленам, реализованным в том же файле.Рис. 5-12. Значок управления доступомFoodItem в свою очередь содержит от одного до двадцати трехзакрытых экземпляров класса VitaminContent (содержание витаминов) иодин открытый экземпляр класса CaloricEquivalent (калорийность).Заметим, что CaloricEquivalent мог бы быть записан как атрибут классаFoodItem, так как атрибуты эквивалентны агрегации, мощность которойравна 1:1.