Главная страница

UML2 и унифицированный процесс. Джим арлоуайла нейштадтпрактический объектно ориентированныйанализ и проектированиеu


Скачать 6.08 Mb.
НазваниеДжим арлоуайла нейштадтпрактический объектно ориентированныйанализ и проектированиеu
АнкорUML2 и унифицированный процесс.pdf
Дата08.04.2018
Размер6.08 Mb.
Формат файлаpdf
Имя файлаUML2 и унифицированный процесс.pdf
ТипДокументы
#17801
страница39 из 62
1   ...   35   36   37   38   39   40   41   42   ...   62
Рис. 17.7. Верная модель

382
Глава 17. Проектные классы скольку его всегда можно заменить единичным наследованием и делегированием. Даже несмотря на то, что иногда множественное на следование предлагает более элегантное решение задачиы проектиро вания, оно может использоваться, только если целевой язык реализа ции его поддерживает.
О множественном наследовании важно знать следующее.
Родители должны быть семантически не связанными.

Все участвующие родительские классы должны быть семантически не связанными. В случае наличия какого либо совмещения в семан тике базовых классов между ними возможны непредвиденные вза имодействия. Это может привести к необычному поведению подклас са. Мы говорим, что базовые классы должны быть ортогональными
(расположенными под прямым углом друг относительно друга).

Между подклассом и всеми его суперклассами должны действовать принцип замещаемости и принцип «является разновидностью».

У суперклассов не должно быть общих родителей. В противном слу чае в иерархии наследования образуется цикл и возникает множест во путей наследования одних и тех же возможностей от более абст рактных классов. У языков программирования, поддерживающих множественное наследование (таких как С++), есть специальные,
особые для каждого языка способы разрешения циклов в иерархии наследования.
Смешанные классы создаются, чтобы путем множественного наследова ния быть «смешанными» с другими классами. Это надежное и мощное средство.
Один из общепринятых способов эффективного использования множе ственного наследования – «смешанный» (mixin) класс. Эти классы не являются по настоящему автономными классами. Они разрабатыва ются специально для того, чтобы быть «смешанными» с другими клас сами с помощью наследования. На рис. 17.8 класс
Dialer (набиратель номера) – простой смешанный класс. Его единственная функция –
набор телефонного номера. То есть сам по себе он не представляет осо бой ценности, но предоставляет связный пакет полезного поведения,
Dialer
Alarm
AlarmDialer
Рис. 17.8. Смешанный класс Dialer

17.7. Шаблоны
383
которое может широко использоваться другими классами посредством множественного наследования. Этот смешанный класс – пример обыч ного утилитного класса, который мог бы стать частью многократно ис пользуемой библиотеки.
17.6.3. Сравнение наследования и реализации интерфейса
При наследовании мы получаем две вещи:

интерфейс – открытые операции базовых классов;

реализацию – атрибуты, отношения, защищенные и закрытые опе рации базовых классов.
При реализации интерфейса (глава 19) получаем только одно:

интерфейс – набор открытых операций, атрибутов и отношений,
не
имеющих реализации.
У наследования и реализации интерфейса есть что то общее, посколь ку оба этих механизма обеспечивают возможность описания контрак та, который должен быть реализован подклассами. Однако семантика и применение этих двух методов совершенно разные.
Наследование должно использоваться только тогда, когда речь идет о наследовании от суперкласса некоторых деталей реализации (опера ций, атрибутов, отношений). Это одна из разновидностей многократ ного использования. На заре ОО наследование часто считали основным механизмом многократного использования. Однако мир не стоит на месте, и разработчики выявили подчас неприемлемые ограничения,
накладываемые наследованием. Поэтому от его применения несколь ко отошли.
Реализация интерфейса полезна везде, где необходимо определить контракт, но без наследования деталей реализации. Хотя реализация интерфейса фактически не обеспечивает повторного использования кода, она предоставляет безупречный механизм описания контрактов и гарантирует их выполнение классами реализации. Поскольку в реа лизации интерфейса ничего не наследуется, это в некотором отноше нии более гибкий и надежный механизм, чем наследование.
17.7. Шаблоны
До сих пор при описании проектного класса нам приходилось явно за давать типы атрибутов, возвращаемые типы всех операций и типы всех параметров операций. Это нормально и хорошо работает в боль шинстве случаев, но иногда может ограничивать возможность повтор ного использования кода.
В примере на рис. 17.9 описаны три класса. Все три являются ограни ченными массивами. Один из массивов типа int, следующий – double и последний –
String. Внимательно посмотрев на эти классы, можно за

384
Глава 17. Проектные классы метить, что они идентичны, за исключением типа элементов, храня щихся в массиве. Однако, несмотря на это сходство, были определены три разных класса.
Шаблоны (templates) позволяют параметризовать тип. Это означает, что вместо определения фактических типов атрибутов, возвращаемых зна чений операций и параметров операций можно описать класс с помо щью структурных нулей (placeholder), или параметров. При создании новых классов они могут быть заменены фактическими значениями.
На рис. 17.10 класс
BoundedArray описан с помощью параметров type
(тип) (который по умолчанию является классификатором) и size (раз мер) типа int. Обратите внимание, что шаблон определяет для size при меняемое по умолчанию значение
10. Это значение используется, если при создании экземпляра шаблона размер не будет задан.
Связывая конкретные значения с этими формальными параметрами,
можно создавать новые классы. Это называют созданием экземпляра шаблона. Заметьте, что в результате создания экземпляра шаблона по лучается класс, экземпляры которого можно затем создавать для по лучения объектов.
Как показывает рис. 17.10, экземпляр шаблона можно создать с помо щью отношения реализации, обозначенного стереотипом
«bind» (свя зать); это называют явным связыванием. Чтобы создать экземпляр шаблона, необходимо задать фактические значения, которые будут при
BoundedIntArray size : int elements[ ] : int addElement( e:int ) : void getElement( i:int ) : int
BoundedDoubleArray size : int elements[ ] : double addElement( e:double ) : void getElement( i:int ) : double
BoundedStringArray size : int elements[ ] : String addElement( e:String ) : void getElement( i:int ) : String
Рис. 17.9. Три класса отличаются только типом элементов
StringArray elements[10] : String addElement( e:String ) : void getElement( i:int ) : String
IntArray elements[100] : int addElement( e:int ) : void getElement( i:int ) : int
«bind» < type >String >
«bind» < type >int, size >100 >
параметры шаблона шаблон явное связывание применяемое по умолчанию значение
BoundedArray elements[size] : type type, size : int = 10
addElement( e:type ) : void getElement( i:int ) : type
Рис. 17.10. Создание экземпляра шаблона с помощью явного связывания

17.7. Шаблоны
385
своены параметрам шаблона. Их указывают в угловых скобках после стереотипа
«bind». При создании экземпляра шаблона его параметры будут заменены этими значениями, в результате получится новый класс. Обратите внимание на синтаксис связывания параметров: вы ражение type >int означает, что параметр шаблона type при создании экземпляра замещается int. Символ > можно прочитать как «замеща ется» или «связывается».
Очевидно, что шаблоны являются мощным механизмом многократно го использования кода. Класс можно описать как шаблон, в общих чертах, и затем создавать множество его специальных версий, присва ивая параметрам шаблона соответствующие реальные значения.
На рис. 17.10 связывание на самом деле используется двумя способами.
Во первых, классификатор связывается с параметром type. Если у пара метра шаблона нет типа, то по умолчанию это классификатор. Во вто рых, параметру size присваивается реальное целое значение. Это позво ляет задавать размер ограниченного массива как параметр шаблона.
В рамках конкретного шаблона имена параметров являются локаль ными. Это означает, что если у двух шаблонов есть параметр type, в каж дом случае это разные параметры type.
Существует разновидность синтаксиса шаблонов, которую называют неявным связыванием. Здесь для представления создания экземпляра шаблона не используется явная реализация
«bind», но происходит не явное связывание за счет применения специального синтаксиса в по лучаемых классах. Чтобы неявно создать экземпляр шаблона, факти ческие значения перечисляют в угловых скобках после имени класса шаблона, как показано на рис. 17.11. Недостаток этого подхода в том,
что получаемому в результате классу нельзя присвоить имя.
По нашему мнению, лучше использовать явное связывание, чтобы классы, получаемые в результате создания экземпляров шаблона,
могли иметь собственные описательные имена.
Хотя шаблоны – очень мощная возможность, в настоящее время C++
и Java являются единственными распространенными ОО языками про граммирования, которые их поддерживают (табл. 17.1). Понятно, что шаблоны могут использоваться при проектировании только в том слу чае, если они поддерживаются языком реализации.
BoundedArray elements[size] : type addElement( e:type ) : void getElement( i:int ) : type
BoundedArray< type >String >
elements[10] : String addElement( e:String ) : void getElement( i:int ) : String неявное связывание type, size : int = 10
Рис. 17.11. Создание экземпляра шаблона посредством неявного связывания

386
Глава 17. Проектные классы
Таблица 17.1
17.8. Вложенные классы
Вложенный класс – это класс, определенный внутри другого класса.
Некоторые языки программирования, такие как Java, позволяют раз мещать описание класса внутри описания другого класса. Таким обра зом, создается так называемый вложенный класс. В Java их также на зывают внутренними классами (inner class).
Вложенный класс объявляется в пространстве имен его внешнего класса и доступен только для этого класса или объектов этого класса.
Только внешний класс или его объекты могут создавать и использо вать экземпляры вложенного класса.
Вложенные классы, как правило, относятся к вопросам проектирова ния. Здесь речь идет о том, как может быть реализована некоторая функциональность, а не что она из себя представляет.
Например, вложенные классы широко используются в Java при обра ботке событий. Пример на рис. 17.12 показывает простой класс окна
HelloFrame (окно приветствия). Базовое поведение окна он наследует от своего родительского класса
Frame. В HelloFrame есть вложенный класс
Язык программирования
Поддержка шаблонов
Java
Да
C++
Да
Smalltalk
Нет
Python
Нет
Visual Basic
Нет
C#
Нет
MouseAdapter
Frame
HelloFrame
MouseMonitor пиктограмма якоря отношение включения
Рис. 17.12. Класс MouseMonitor вложен в класс HelloFrame

17.9. Что мы узнали
387
MouseMonitor (монитор мыши), который от своего родителя MouseAdapter наследует способность обрабатывать события мыши.
Каждый экземпляр
HelloFrame использует экземпляр MouseMonitor для обработки событий мыши. Для этого экземпляр
HelloFrame должен:

создать экземпляр класса
MouseMonitor;

определить этот экземпляр
MouseMonitor слушателем событий мыши.
Такой подход является хорошим стилем проектирования. Код обра ботки событий мыши выносится из остального кода
HelloFrame в отдель ный класс
MouseMonitor. И MouseMonitor полностью инкапсулирован в
HelloFrame.
17.9. Что мы узнали
Проектные классы – это строительные блоки проектной модели. Мы изучили следующее:

Проектные классы разрабатываются в деятельности UP
Проектиро вание класса.

Проектные классы – это классы, описанные настолько полно, что могут быть реализованы.

Существует два источника проектных классов:

предметная область:

уточнение классов анализа;

один класс анализа может превратиться в нуль, один или бо лее проектных классов;

область решения:

библиотеки утилитных классов;

промежуточное программное обеспечение;

библиотеки GUI;

многократно используемые компоненты;

детали, характерные для конкретной реализации.

Проектные классы имеют полные описания:

полный набор атрибутов, включающий:

имя;

тип;

применяемое по умолчанию значение, когда это необходимо;

видимость;

операций:

имя;

имена и типы всех параметров;

необязательные значения параметров, если это необходимо;

388
Глава 17. Проектные классы

возвращаемый тип;

видимость.

Правильно сформированные проектные классы имеют следующие характеристики:

открытые операции класса определяют контракт с клиентами класса;

полнота – класс делает не менее того, что его клиенты могут обоснованно ожидать;

достаточность – класс делает не более того, что его клиенты мо гут обоснованно ожидать;

простота – сервисы должны быть простыми, элементарными и уникальными;

высокая внутренняя связность:

каждый класс должен реализовывать единственное четко оп ределенное абстрактное понятие;

все операции должны быть направлены на реализацию пред назначения класса;

низкая связанность с другими классами:

класс должен быть взаимосвязан с таким количеством клас сов, которого достаточно для реализации его обязанностей;

между двумя классами должно устанавливаться взаимоотно шение, только если между ними существует настоящая се мантическая связь;

необходимо избегать использования связанности только с це лью повторного использования некоего кода.

Проектный класс всегда необходимо оценивать с точки зрения клиентов этого класса.

Наследование.

Наследование должно использоваться только тогда, когда меж ду двумя классами существует четкое отношение «является»
или с целью повторного использования кода.

Недостатки:

это самая строгая из возможных форм связанности между двумя классами;

в рамках иерархии наследования инкапсуляция слаба, что приводит к проблеме «хрупкости базового класса» – измене ния базового класса передаются вниз по иерархии;

является очень негибкой формой отношений в большинстве языков программирования – отношение устанавливается во время компиляции и остается неизменным во время выпол нения.

17.9. Что мы узнали
389

Подклассы всегда должны представлять «разновидность», а не
«исполняемую роль» – для представления «исполняемой роли»
должна использоваться агрегация.

Множественное наследование позволяет классам иметь более одно го родителя.

Из всех широко используемых ОО языков программирования только C++ поддерживает множественное наследование.

Рекомендации к проектированию:

все родительские классы при множественном наследовании должны быть семантически не связанными;

между классом и всеми его родителями должно быть установ лено отношение «является разновидностью»;

к классу и его родителям должен применяться принцип заме щаемости;

у самих родительских классов не должно быть общих родите лей;

используйте смешанные классы – простые классы, разрабо танные для смешивания с другими классами при множест венном наследовании; это надежное и мощное средство.

Сравнение наследования и реализации интерфейса.

Наследование:

получаем интерфейс – открытые операции;

получаем реализацию – атрибуты, ассоциации, защищенные и закрытые члены.

Реализация интерфейса – получаем только интерфейс.

Наследование должно применяться, когда необходимо унаследо вать некоторую реализацию.

Реализация интерфейса должна применяться, когда необходимо определить контракт.

Шаблоны.

Из всех широко используемых ОО языков программирования в настоящее время шаблоны поддерживают только C++ и Java.

Шаблоны позволяют «параметризовать» тип – шаблон создается путем определения типа с помощью формальных параметров,
и экземпляры шаблона создаются через связывание параметров с конкретными значениями.

Явное связывание использует зависимость, обозначенную сте реотипом
«bind»:

фактические значения показаны на отношении;

каждому экземпляру шаблона можно присвоить имя.

390
Глава 17. Проектные классы

Неявное связывание:

фактические значения задаются в угловых скобках (
< >)
прямо в классе;

экземплярам шаблона имена присвоить нельзя – имена об разуются именем шаблона и списком аргументов.

Вложенные классы:

класс определяется внутри другого класса;

вложенный класс существует в пространстве имен внешнего класса – только внешний класс может создавать и использовать экземпляры вложенного класса;

в Java вложенные классы называются внутренними классами;
их активно используют для обработки событий в классах GUI.

18
Уточнение отношений,
выявленных при анализе
18.1. План главы
В этой главе обсуждаются методы уточнения (детализации) отноше ний, выявленных при анализе, в отношения уровня проектирования.
Эти методы используются во всех деятельностях рабочего потока про ектирования (рис. 16.6).
В первой части данной главы обсуждается преобразование отношений уровня анализа в одно из отношений целое часть – агрегацию (раз дел 18.4) или композицию (раздел 18.5).
Вторая часть посвящена работе с кратностью аналитических ассоциа ций. Мы предлагаем конкретные методы уточнения аналитических ассоциаций с кратностью один к одному (раздел 18.7), многие к одно му (раздел 18.8), один ко многим (раздел 18.9) и многие ко многим
(раздел 18.11.1). Также рассматриваются двунаправленные ассоциа ции (раздел 18.11.2) и классы ассоциации (раздел 18.11.3).
В завершение мы увидим, как с помощью UML 2 можно устанавливать отношение между составным классификатором и его частями.
1   ...   35   36   37   38   39   40   41   42   ...   62


написать администратору сайта