Дж. Рамбо, М. Блаха - UML 2.0 - Объектно-ориентированное моделирование и разработка (1158633), страница 96
Текст из файла (страница 96)
Удаление связи Удаление связи означает процедуру, обратную ее созданию. Ссылка обычно разрывается тем методом, действия которого приводят к разрушению ассоциации. В большинстве случаев это означает, что атрибут-ссылка устанавливается равным нулю или что из совокупности ссылок изымается один элемент. 400 Глава 18 е Обьектно-ориентированные языки Например, студент (5Гидепг) из нашего примера может прекратить слушать курс лекций (Соигзе). // Зиибепо.бгорС1авв(Соигзе): риь11о Ьоа1еап бгорС1азв(Соигзе огз) ЕЕ ((с1аввез.сопвагпь(огз)) гевигп Еа1зе; ЕЕ (!огз.бгор(ГЬ1з)) гевигп Еа1зе; о1азвез.гевоче(с1аззев.бпбехОЕ(огз))) гегигп ггие; ) // Соигзе.бгор(эгибепг): Ьоо1еап бгор(явибепв зги) ( ЕЕ ((вгибепгв.оопгагпв(вги)) гегигп Еа1ое) зоибепив.геаоче(зоибепов.
1пбехОЕ(веи))) гегигп ггие) Если связи были созданы между уже существовавшими объектами, эти объекты, скорее всего, продолжат существовать и после уничтожения связей. Нужно следить за тем, чтобы объект, на который ссылался другой объект, был доступен по каким-либо ссылкам после уничтожения связи. В противном случае может возникнуть утечка памяти в С++, или же объект, оставшийся без ссылок на него, будет уничтожен сборщиком мусора в ) ача. В С++ создание и уничтожение связей осуществляется парой конструктор-деструктор. Эти связи обычно отражают захват и освобождение ресурсов. Связи между объектами, существование которых зависит друг от друга, могут требовать удаления одного из объектов при разрыве.
Это, в свою очередь, может потребовать удаления или обновления других обьектов, связанных с уничтожаемым. Здесь можно провести аналогию с базами данных, где удаление записи может каскадно распространиться на связанные с ней записи или быть запрещено для сохранения цельности существующих записей.
18А.б. Производные атрибуты Для достижения точности и актуальности желательно рассчитывать значения производных атрибутов по независимым атрибутам в момент обращения к первым. Обычно время, затрачиваемое на это вычисление, пренебрежимо мало по сравнению с затратами на регулярное обновление и на хранение избыточных данных. Широко распространена ошибка, связанная с включением в объекты избыточных данных о состоянии. Состояние часто можно определить по значениям остальных атрибутов ()ача): риЬ1гс с1авв Аоооипв ( // неправильно: избыточные данные для счета о превыыениеи кредита рг1чаге Ьоо1еап очегбгачп; рг1чаге Е1оаг Ьа1апое) // правильно: определение состояние счета по запросу риь11о Ьоо1еап 1всчегбганп() ( гееигп Ьа1апое < Гы 18.5.
Практические рекомендации 403. Состояние объекта можно определить и по его связям (С++): с1авв Спапошег ( ьгвс<дссоопс> ассов; рпЬ11с: Ьоо1 Ьавбчегбганплссоопп() ( // пеРебоР всех счетов клиента // вовврашение Сгче в случае наличия счетов // с превышением кредита ! Или же состояние может зависеть от существования или отсутствия связей (С++): с1авв Те1ерьопе ( Те1ерьопе* соппессебто) рпьттс: // есть ли соединение с другим телефоном? // если ссылка ненулевая, то есть Ьоо1 1вэову() ( седого соппеспебто ! 0~ 18.5.
Практические рекомендации Вот н есколько советов по реализации проектов на С++ и )ача. Перечисления. Используйте перечислимые типы для повышения ясности кода и ограничения возможных значений (раздел 18.3.1). Пакеты Дача. Не используйте пакет по умолчанию.
Указывайте имена пакетов и с их помощью управляйте доступом (раздел 18.3.3). Управление доступом. Объявляйте все атрибуты и недоступные другим классам методы как закрытые — р)тоаге. Ослабляйте ограничение только в том случае, если для этого есть веские основания (раздел 18.3.3). Дружественные классы. Воздерживайтесь от использования специфика- тора у)теЫ в С++, потому что он нарушает инкапсуляцию (раздел 18.3.3). Интерфейсы )ача.
Реализуйте множественное наследование посредством интерфейсов. Интерфейс объявляет методы и постоянные атрибуты, а также позволяет указывать тип объектов (раздел 18.3.4). Закрытое наследование в С++. Избегайте закрытого наследования классов. Вместо него лучше использовать делегирование (раздел 18.3А). Односторонние ассоциации.
Используйте односторонние ассоциации везде, где нет необходимости в прослеживании связи в двух направлениях. Односторонние ассоциации легче поддерживать, они сокращают взаимную зависимость объектов (раздел 18.3.5). Ссылки С++ и квалификатор йпа! в Дача. Обращайте внимание на полюса ассоциаций, которые должны быть привязаны к объектам в момент 402 Глава 18 ° Объектно-ориентированные языки инициализации и не подлежат дальнейшим изменениям. Эта семантика полностью сохраняется ссылками С++ и частично реализуется посредством квалификатора /та1 в Дача (раздел 18.3.5). ° Конструкторы.
Отсутствие явно определенного конструктора в классе считается плохим стилем программирования. Конструктор обеспечивает инициализацию объекта и перевод его в корректное начальное состояние (раздел 18.4.1). ° Удаление в С++. После удаления объекта в С++ рекомендуется сразу же обнулить все указатели на этот объект во избежание случайного повторного его удаления, которое может привести к катастрофическим последствиям (раздел 18 4.3). ° Удаление связи. При удалении связи желательно следить за доступностью участвовавших в ней объектов или контролировать их удаление, если оно необходимо.
В противном случае возникнет утечка памяти в С++, или же объект может быть непредвиденно удален сборщиком мусора ) ача (раздел 18.4.5). 18.6. Резюме Реализовать объектно-ориентированный проект на объектно-ориентированном языке относительно легко, потому что конструкции языка близки конструкциям модели. В этой главе мы рассмотрели два наиболее популярных объектно-ориентированных языка: С++ и )ача. Первый этап воплощения объектно-ориентированного проекта — реализация структуры модели классов.
Сначала следует задать тип всех атрибутов. Везде, где это возможно, вместо строковых значений лучше использовать числовые. Числовые типы лучше размещаются в памяти и более эффективно обрабатываются, а также облегчают контроль согласованности атрибутов. Затем следует определить сами классы. Лучше всего начинать с общедоступного интерфейса класса, а затем добавлять внутренние методы, атрибуты и встроенные классы, необходимые для реализации методов интерфейса.
Особое внимание следует уделять управлению доступом. Контроль доступа позволяет инкапсулировать атрибуты и методы и ограничить обращения к ним. Основные спецификаторы доступа в С++ и )ача совпадают. Закрытые члены класса доступны только его собственным методам. Открытые члены класса доступны всем клиентам. Спецификатор рго1есгеп' в С++ открывает доступ самому классу и его подклассам. В )ача защищенные (ргосессес1) члены доступны методам того же пакета.
Таким образом, пакеты ) ача служат не только для упорядочения кода, но и для управления доступом. Объявление дружественности в С++ ((г(епс() позволяет организовать выборочный доступ к закрытым членам класса. Объектно-ориентированные языки позволяют реализовать обобщение через наследование. С++ поддерживает множественное наследование непосредственно, а )ача — посредством концепции интерфейсов.
Интерфейс ) ача — это спецификация класса, из которой полностью исключены детали реализации. Полиморфизм в )ача осуществляется автоматически. Порождение подклассов можно запретить посредством квалификатора Впа1. Этот квалификатор, приме- Литература 403 таблица 18.2. Ключевые понятия главы абстрактный модификатор доступа спецификатор доступа ассоциация конкретный конструктор тиц данных рг!часе производные данные деструктор пакет указатель полиморфизм ссылка чсгща! зсас!с ргосессес! песч !пгег!асе 1г!епй перечисление сборка мусора обобщение йпа! рцЫк пространство имен перегрузка Библиографические замечания В книге !Всгоцзсгцр-94! обсуждаются вопросы, связанные с реализацией проек- тов на языках программирования. Литература [Агпо1ц-00] Кеп Агпо!ц', )агпез Ооз!!пя, апс! Оач!с! Но1спез.
Т!се 1ача Ргоягатсп!пя 1.апяцаце, Т!с!гс! Ес1!с!оп. Возсоп: Ас!ц!зоп-'чч'ез!еу, 2000. пенный к методам, предотвращает их перекрытие. В С++ полиморфизм управляется программистом при помощи квалификатора иггиаб Объектно-ориентированные языки не имеют встроенной поддержки ассоциаций.
Однако их можно легко реализовать посредством указателей или ссылок или выделенных объектов-ассоциаций. Односторонние ассоциации сокращают взаимную зависимость классов, поэтому их следует использовать всегда, когда прослеживание планируется осуществлять только в одном направлении. С++ позволяет реализовать полюса ассоциации двумя способами. Указатель позволяе~ изменять связь или делать ее нулевой, тогда как ссылка получает свое значение в момент инициализации и не может быть изменена или сделана нулевой. В )ача можно объявить атрибут объектного типа как усла1, что запрещает изменение связи, но не требует ее изначальной инициализации.
Если ассоциацию нужно прослеживать в двух направлениях, используйте двустороннюю. реализацию. Вы можете добавить указатель или ссылку (или множество указателей или ссылок) в каждый класс или создать отдельный объект-ассоциацию. Двусторонние указатели создают определенную избыточность, поэтому необходимо внимательно следить за их согласованностью. Закончив реализацию структуры модели классов, переходите к реализации методов. Аккуратно определяйте конструкторы объектов, обеспечивайте корректную инициализацию. Столь же внимательно слелует относиться и к деструкторам, не забывать освобождать системные или программные ресурсы.