Дж. Рамбо, М. Блаха - UML 2.0 - Объектно-ориентированное моделирование и разработка (1158633), страница 83
Текст из файла (страница 83)
После этого один объект сможет вызывать нужные операции другого класса, используя делегирование. Делегирование (де1еяаВоп) — это перехват операции в одном объекте и отправка ее связанному объекту. Делегирование осуществляется только для тех операций, которые имеют смысл в контексте данного объекта, поэтому опасности случайно унаследовать не имеющие смысла операции просто нет.
Более безопасный вариант класса 5гасй может делегировать операции классу ьмг (рис. 15.7). Каждый экземпляр класса 5гао( содержит закрытый экземпляр класса 7.мг. Фактическую реализацию можно оптимизировать, используя встроенный объект или атрибут-указатель. Операция 5гасй.ризл() делегируется объекту 7.мг вызовом его операций Бигли и а~Ы(7, посредством которых осуществляется добавление элемента в конец списка.
Операция 5гас1ьрор(7 реализуется аналогичным образом посредством операций Ыг() и гетосе(). Возможность повреждения стека из-за добавления или удаления произвольных элементов в данном случае скрыта от клиентов класса 5гасй. 15.10. Органиэация проекта модели классов 345 В некоторых языках, таких как С++ и) ача, подкласс может наследовать форму суперкласса с выборочным наследованием операций предков и выборочным предоставлением операций клиентам. Это равносильно делегированию, потому что подкласс при этом не является частным случаем суперкласса и не может заменять его.
Рваомендуемый вариант Не рекомендуемый вариант (с делеаированием) (с наследованием в целан реализации) Рис. 15.7. Альтернативные варианты проектирования Пример с банкоматом. Наша иерархия наследования имеет глубокую и четкую структуру. Именно к такому наследованию и нужно стремиться. 15.10. Организация проекта модели классов Программы состоят из дискретных физических блоков, которые можно редактировать, компилировать, импортировать и использовать другими способами. В некоторых языках, таких как С и гогггап, блоками являются файлы исходного кода.
В Ада и )ача имеется явно определенная языковая конструкция под названием расйаде (пакет). В работе 1Сорйеп-921 показано, как можно использовать класс С++ для группировки статических функций-членов, вложенных классов, перечислений и констант. Организацию проекта модели классов можно усовершенствовать следующими способами: ° сокрытие внутренней информации от доступа извне; ° контроль согласованности сущностей; ° коррекция определений пакетов. 15.10.1. Сокрытие информации На этапе анализа мы не учитывали видимость информации, потому что нам было важнее понять устройство приложения. Цели этапа проектирования несколько иные: аналитическая модель изменяется так, чтобы облегчить реализацию и обслуживание. На жизнеспособность проекта сильно влияет отделение внешней спецификации от внутренней реализации.
Это называется сокрытием информации (Ыоппас)оп 346 Глава 15 ° Проектирование классов Ъ|йпй). Благодаря этому принципу вы можете изменять реализацию класса, не беспокоясь о том, что вам придется изменять код его клиентов. Возникающие в результате границы между классами ограничивают влияние изменений, благодаря чему вам становится легче предсказывать возможные результаты этих изменений.
Существует несколько способов сокрытия информации. ° Ограничение области прослеживания модели классов. В предельном случае метод может проследить все ассоциации модели классов, чтобы найти объект и обратиться к нему. Неограниченная видимость допустима на этапе анализа, но в реализации методы, «знающие» о модели слишком много, оказываются недолговечными и сильно страдают от изменений в модели.
В процессе проектирования нужно стремиться ограничивать область, прослеживаемую каждым из методов ~ЫеьегЪегг-88]. Объект должен обращаться только к непосредственно связанным с ним объектам (между ними должны быть прямые ассоциации). Объект может обращаться к косвенно связанным объектам только посредством методов промежуточных объектов. ° Исключение прямого обращения к чужим атрибутам.
Вообще говоря, подклассы могут обращаться к атрибутам своих суперклассов. Но вот обращения к атрибутам через ассоциации допускать не следует. Вместо этого нужно вызывать операции тех классов, атрибуты которых нужно прочесть или изменить. ° Проектирование интерфейсов на высоком уровне абстрагирования. Нужно стремиться минимизировать связи между классами. Для этого можно, в частности, повышать уровень абстрагирования интерфейсов. Можно вызвать метод другого класса для выполнения важной операции, но не стоит беспокоить его по мелочам. ° Сокрытие внешних объектов. Используйте пограничные объекты для изоляции внутренней части системы от ее внешнего окружения.
Пограничным называется объект, который обеспечивает пересылку запросов и ответов между внутренними и внешними объектами. Пограничный объект принимает внешние запросы в форме, удобной для клиентов, и преобразует их в форму, удобную для внутренней реализации. ° Избегайте каскадных вызовов методов. Не лопускайте применения метода к результатам, возвращаемым другим методом, за исключением тех случаев, когда класс результата уже является поставщиком методов по отношению к вызывающему классу. Вместо этого напишите метод, который будет сочетать обе операции.
15.10.2. Согласованность сущностей Созласованвость — одно из важнейших качеств, которыми должен обладать проект. Сущность, такая как класс, операция или пакет, является внутренне согласованной, если она устроена по некоторому логичному плану и если все ее составляющие работают вместе для достижения единой цели. Сущность должна иметь одну общую тему; она не может быть совокупностью несвязанных частей. Метод должен хорошо делать какое-то одно действие. Один метод не должен содержать и политику, и реализацию. Г1олитика (ройсу) — это принятие решений 15.10.
Организация пооекта модели классов 347 в зависимости от контекста. Реализация (ппр!ешепсас>оп) — это выполнение полностью определенных алгоритмов. Политика подразумевает принятие решений, получение глобальной информации, взаимодействие с внешним миром и интерпретацию частных случаев. Методы, определяющие политику, содержат операции ввода-вывода, обращения к данным и условные операторы. В таких методах нет сложных алгоритмов, но есть вызовы других методов, реализующих нужные алгоритмы. Метод-реализация должен представлять собой код ровно одного алгоритма без всяких решений, предположений, значений по умолчанию или отклонений.
Все данные поступают в виде аргументов, поэтому список аргументов у такого метода может быть довольно большим. Отделение политики от реализации значительно увеличивает вероятность повторного использования. Методы-реализации не содержат никакой зависимости от контекста, а потому могут быть с легкостью задействованы в другой ситуации.
Методы-политики обычно приходится переписывать, ориентируясь на специфику нового приложения, но к счастью они обычно получаются достаточно простыми и состоят, главным образом, из высокоуровневых решений и низкоуровневых вызовов. Рассмотрим в качестве примера операцию, начисляющую проценты на счет «до востребования». Проценты начисляются ежедневно, но если счет закрывается, все проценты за месяц теряются. Программная логика начисления процентов состоит из двух частей: метода-реализации, который начисляет проценты по двум заданным датам, без учета штрафов или иных изменений, и метода-политики, который принимает решение, на каком временном промежутке следует вызывать метод-реализацию. Метод-реализация будет достаточно сложным, но вероятность его повторного использования велика.
Метод-политика вряд ли будет использован повторно, но зато его проще написать. Один класс не должен одновременно служить слишком большому количеству целей. Если класс получается слишком сложным, его можно разбить, используя обобщение или агрегацию. НеГ>ольшие составляющие имеют больше шансов на повторное использование, чем крупные блоки. Точные числа указать достаточно сложно, но в качестве простого правила можно использовать следующее: класс следует разбить, если он содержит более 10 атрибутов, 10 ассоциаций или 20 операций. Всегда разбивайте класс, если атрибуты, ассоциации или операции явно распадаются на несколько несвязанных групп.
15.10.3. Коррекция определений пакетов В процессе анализа вы разГ>или модель классов на пакеты. Первоначальный способ разбиения может быть не самым удачным с точки зрения реализации. Пакеты нужно определять так, чтобы их интерфейсы были как можно проще и при этом были бы как можно лучше определены. Интерфейс между двумя пакетами состоит из ассоциаций, которые связывают классы одного пакета с классами другого, и операций, которые обращаются к классам через границы пакетов. В процессе формирования пакетов можно руководствоваться связностью модели классов. В качестве грубого правила подойдет следующее: классы, тесно 348 Глава 15 ° Проектирование классов ЕпгегебОп Тгапвасбоп * Сазпегйесе!р! ба1еТчпе 1 роз!Тгапас1юп 0..1 Епо уВ!аиоп йегпо!е Аи!Ьопвебву Тгапзас1юп * СавЫег Тгапзасбоп (огбегеб) Сиз!о!пег Црба1е ЕпгегебВу 1 АТМ 0..1 алкам кыб йесегр! савЬОпиапб СавыегЗ!абоп СавЫег чеп!уСавЬСагб чепгуАпюип1 6ВЬигсерипбв гасе!чеЕипбв ров!Тгапасбоп 0..1 пегое 0..1 Егер/оуз 0..1 СазЬСап1 вела!Иигпьег 1 в!авоп Собе Сап1 Аиипобааиоп 1 в1авоп Собе егор!оуе Собе разввгогб !!гпа Вала Сопвогбигп аббАссоип! гегпочеАссоип1 сагзе паве сагб Собе 1 !звиез 0..1 чег!ГТВапКСобе чепГуравееогб сгеа!евач!пдзАссоип! сгеа!еСЬемпдАссоип! сгеа1еСазЬСагб чег!ГуАгпоип! ЬапКСобе 0,.1 Сиз!о!пег ассоип!Себе Ассоипг паве абгезз !егпрАгпоип! Ьа!апсе сгебаЬ!гпа !уре 0..1 де1 Апкгип! е1 Ассоип! с!озе чепГТАгпоип! роз! Рис.
1В.В. Модель классов предметной области банкомата связанные друг с другом ассоциациями, должны находиться в одном пакете, тогда как классы, связанные слабо или ие связанные вовсе, могут быть в разных пакетах. Конечно, нужно учитывать и другие аспекты. Пакет должен иметь определенную тему, обладать функциональным единством. Количество операций, прослеживаюших некоторую ассоциацию, является удобной мерой важности соответствуюшей связи между классами.