UML2 и унифицированный процесс. Джим арлоуайла нейштадтпрактический объектно ориентированныйанализ и проектированиеu
Скачать 6.08 Mb.
|
Рис. 19.2. Деятельность UP Проектирование подсистемы. Адаптировано с рис. 9.44 [Jacobson 1] с разрешения издательства Addison Wesley 422 Глава 19. Интерфейсы и компоненты Таблица 19.1 Атрибуты и операции в интерфейсе должны быть полностью описаны и включать следующее: • полную сигнатуру операции (имя, типы всех параметров и возвра щаемый тип); • семантику операции – она может быть записана в виде текста или псевдокода; • имена и типы атрибутов; • все стереотипы, ограничения или помеченные значения операции или атрибута. Важно помнить, что интерфейс определяет только описание своих воз можностей и что он никогда не заключает в себе какой либо конкрет ной реализации. Интерфейсы определяют контракт. Интерфейсы могут иметь огромное влияние на способ проектирования. До сих пор проектирование заключалось в соединении определенных классов. Этот процесс можно было бы назвать «проектирование реали зации». Однако более гибким подходом является «проектирование контракта», когда классы соединяются с интерфейсом, после чего этот интерфейс может быть реализован любым количеством классов и дру Интерфейс описывает Реализующий классификатор Операция Должен иметь операцию с аналогичной сигнатурой и семантикой. Атрибут Должен иметь открытые операции для задания и по лучения значения атрибута – не требуется, чтобы у реализующего классификатора на самом деле был атрибут, определенный интерфейсом, но его поведе ние должно быть таким, как будто он существует. Ассоциация Должен иметь ассоциацию с целевым классифика тором – если интерфейс описывает ассоциацию с другим интерфейсом, классификатор, реализую щий эти интерфейсы, должен реализовывать ассо циацию между ними. Ограничение Должен поддерживать ограничение. Стереотип Имеет стереотип. Помеченное значение Имеет помеченное значение. Протокол (например, оп ределенный конечным автоматом протокола – см. раздел 21.2.1) Должен реализовывать протокол. 19.4. Предоставляемые и требуемые интерфейсы 423 гих классификаторов. Стандартные библиотеки Java являются свиде тельством гибкости и мощи такого подхода. Часто говорят, что интер фейс определяет сервис, предлагаемый классом, подсистемой или ком понентом. Современные программные архитектуры часто основывают ся на сервисах. Если язык реализации не поддерживает интерфейсы непосредственно, используйте абстрактные классы. Язык Java первым из широко используемых языков программирова ния ввел специальную языковую конструкцию для интерфейсов. Од нако интерфейсы вполне могут использоваться при программирова нии на языках, не имеющих такой специальной конструкции. Напри мер, в С++ просто описывается полностью абстрактный класс, т. е. аб страктный класс, все операции которого абстрактны. 19.4. Предоставляемые и требуемые интерфейсы Реализуемый классификатором набор интерфейсов называют предо ставляемыми (provided) интерфейсами. Реализуемые классификаторами интерфейсы являются предоставляе мыми интерфейсами. Интерфейсы, необходимые для работы классификатора, называют требуемыми (required) интерфейсами. Необходимые классификатору интерфейсы – это требуемые интерфейсы. На рис. 19.3 показаны два варианта UML синтаксиса для предостав ляемых интерфейсов: нотация в стиле «класса» (в которой можно по Нотация в стиле «леденец на палочках» (примечание: в этой краткой нотации нельзя показать операции или атрибуты) Нотация в стиле «класса» интерфейс отношение реализации borrow() Book CD Book CD Borrow «interface» Borrow return() isOverdue() Рис. 19.3. Два варианта синтаксиса для предоставляемых интерфейсов 424 Глава 19. Интерфейсы и компоненты казывать атрибуты и операции) и краткая нотация в стиле «леденец на палочках» (в которой можно не показывать атрибуты и операции). Пример на рис. 19.3 взят из простой системы управления библиотекой, в которой класс обслуживает коллекцию объектов Book и коллекцию объектов CD. Каждый объект Book и CD реализуют интерфейс Borrow, оп ределяющий протокол для позиций, которые могут быть выданы на время. Хотя семантически Book и CD совершенно разные, интерфейс Bor row позволяет Library рассматривать их одинаково, по крайней мере в том, что касается протокола выдачи книг во временное пользование. Обычно имена интерфейсов и классов совпадают; они записываются в стиле UpperCamelCase. Однако в Visual Basic и C# действует обще принятый стандарт – имя каждого интерфейса начинается с большой I, например IBorrow. Другой стиль присваивания имен – добавление в кон це имени суффикса «able», например Borrowable или IBorrowable. Отношение реализации – это отношение между описанием (в данном случае интерфейсом) и тем, что реализует это описание (в данном слу чае классами Book и CD). Позже мы увидим, что не только классы могут реализовывать интерфейс. Это также могут делать и другие классифи каторы, такие как пакеты и компоненты. Обратите внимание, что в нотации в стиле класса отношение реализа ции представляется в виде пунктирной линии с незаштрихованной стрелкой, тогда как в нотации «леденец на палочках» это сплошная линия без стрелки. Главная причина в том, что нотация «леденец на палочках» должна оставаться максимально краткой. Нотацию класса используют, когда хотят показать возможности интерфейса, а нота цию «леденец на палочках» – когда этого делать не надо. Но они обе представляют одно и то же. На рис. 19.4 показан класс Library, которому требуется интерфейс Bor row. Требуемый интерфейс можно показать как зависимость, направ требуемый интерфейс нотация в стиле класса нотация в стиле «леденец на палочках» предпочтительная предпочтительная Borrow Borrow Library Library Library «interface» Borrow Рис. 19.4. Варианты синтаксиса требуемого интерфейса 19.4. Предоставляемые и требуемые интерфейсы 425 ленную к интерфейсу (как в нотации класса, так и в нотации «леденец на палочках»), или как гнездо под требуемый интерфейс. В любом слу чае эта нотация показывает, что Library понимает и требует конкретный протокол, определенный интерфейсом Borrow. Все элементы, реализую щие этот интерфейс, потенциально могут быть подключены к Library, и Library поймет, что они могут быть выданы на время и возвращены. На рис. 19.5 система Library показана в сборке. Разъем сборки указыва ет, что и Book, и CD предоставляют необходимый Library набор сервисов (описанных классом Borrow). Другой хороший пример интерфейсов с множеством реализаций мож но найти в классах коллекциях в стандартных библиотеках Java (рис. 19.6). Хотя там описано всего восемь интерфейсов, Java предос тавляет множество разных реализаций, каждая из которых обладает различными характеристиками. При проектировании интерфейса Ja va проектировщик может перенести фактическую реализацию интер фейса на период реализации и позволить Java программисту выбирать реализацию с наиболее подходящими характеристиками. Library 1 1 Borrow Book CD 0..* 0..* разъем сборки Рис. 19.5. Система Library в сборке Iterable Collection List Set SortedSet Map SortedMap ConcurrentMap Рис. 19.6. Интерфейсы с множеством реализаций в классах коллекциях Java 426 Глава 19. Интерфейсы и компоненты 19.5. Сравнение реализации интерфейса и наследования Реализация интерфейса – «реализует определяемый им контракт». Теперь стоит обсудить, в чем разница между реализацией интерфейса и наследованием. Семантика реализации интерфейса – «реализует оп ределенный контракт», а семантика наследования – «является». Прин цип замещаемости применим как к наследованию, так и к реализации интерфейса. Таким образом, оба типа отношений могут формировать полиморфизм. Семантика наследования – «является». Чтобы проиллюстрировать разницу между реализацией интерфейса и наследованием, мы предлагаем альтернативное решение для систе мы управления библиотекой на основании наследования (рис. 19.7). Оно кажется вполне приемлемым и в некотором отношении даже бо лее простым, но здесь есть некоторые проблемы. Прежде всего обсудим, почему эта основанная на наследовании модель не совсем подходит. Здесь очень четко определяется, что объекты Book и CD имеют тип BorrowableItem. Но разве этой способности Book и CD быть выданными на время достаточно для описания их типа? Наверное, ее можно было бы рассматривать как один из аспектов их поведения, ко торый оказался бы общим в контексте библиотечной системы. Семан тически правильнее рассматривать BorrowableItem как отдельную роль, которую Book и CD играют в Library, а не как общий надтип. Чтобы конкретизировать недостаток модели, изображенной на рис. 19.7, добавим в систему Library класс Journal (журнал). Journal – это периодическое издание, такое как «Nature» (Природа), не выдаваемое Book CD Library 1 0..* BorrowableItem Рис. 19.7. Модель, основанная на наследовании, имеет недостаток 19.5. Сравнение реализации интерфейса и наследования 427 на время. В результате получается основанная на наследовании мо дель, представленная на рис. 19.8. Обратите внимание, что теперь Library должен обслуживать два списка объектов – те, которые могут, и те, которые не могут выдаваться на вре мя. Такое решение работоспособно, но не очень изящно, поскольку в нем смешиваются два очень разных понятия системы Library: • хранящиеся объекты; • объекты, выдаваемые на время. Эту модель можно несколько усовершенствовать, введя дополнитель ный уровень иерархии наследования, как показано на рис. 19.9. Ис пользование класса LibraryItem (библиотечная позиция) избавляет от одного из отношений композиции. Такое решение в принципе под Book CD Library 1 0..* BorrowableItem NonBorrowableItem Journal 1 0..* Рис. 19.8. Модель Library с двумя списками объектов Book CD Library 1 0..* BorrowableItem NonBorrowableItem Journal LibraryItem Рис. 19.9. Усовершенствованная модель Library 428 Глава 19. Интерфейсы и компоненты ходит, поскольку в нем используется только наследование. Протокол «выдаваемый на время» вынесен в отдельный уровень иерархии на следования. Это обычное решение проблемы такого рода. Модель, использующая и интерфейсы, и наследование, обеспечивает более элегантное решение (рис. 19.10). Основанное на интерфейсах решение имеет следующие преимущества: • каждая позиция в Library является LibraryItem; • понятие «возможность выдачи на время» вынесена в отдельный ин терфейс, Borrowable, который может применяться к классам Library Item в случае необходимости; • сокращается число классов – пять классов и один интерфейс в про тивоположность семи классам в другом решении; • меньше отношений композиции – одно в противоположность двум в другом решении; • более простая, состоящая всего из двух уровней, иерархия наследо вания; • меньше отношений наследования – три в противоположность пяти в другом решении. В общем, основанное на интерфейсе решение проще и обладает лучшей семантикой. Такие характеристики, как catalogNumber (номер катало га), которые есть у всех LibraryItem, были вынесены в базовый класс, чтобы обеспечить возможность их наследования. А протокол «возмож ность выдачи на время» определен отдельно в интерфейсе Borrowable. Book CD Library 1 0..* Journal Borrowable LibraryItem Рис. 19.10. Модель Library, использующая и интерфейсы, и наследование 19.5. Сравнение реализации интерфейса и наследования 429 Чтобы проиллюстрировать гибкость интерфейсов, давайте пойдем в этом примере на шаг вперед. Предположим, что необходимо экспор тировать данные классов Book и Journal (но не CD) в XML файлы. Приклад ные драйверы в этом случае должны обеспечивать возможность обмена информацией с другими библиотеками и представления каталога пе чатных материалов в Веб. Было спроектировано следующее решение: • для осуществления экспорта в XML введен класс XMLExporter; • введен интерфейс XMLExportable, определяющий протокол для рабо ты с XMLExporter, который должен быть у каждой экспортируемой позиции. Имеются следующие нефункциональные требования: • языком реализации должен быть Java; • для обработки XML должна использоваться библиотека JDOM (JDOM – простая, но мощная библиотека Java для работы с XML документами; см. www.jdom.org). Протокол XMLExportable – это всего лишь одна операция getElement(), воз вращающая представление экспортируемого элемента в виде класса Element, описанного в библиотеке JDOM. Класс XMLExporter использует JDOM для записи объектов Element в XML файл. Полностью решение представлено на рис. 19.11. Book CD Library 1 0..* Journal Borrowable LibraryItem «interface» XMLExportable getElement():Element XMLExporter writeXMLDocument( filename:String, root:Element, elements:XMLExportable[ ] ) XMLExportable XMLExportable Рис. 19.11. Усовершенствованная модель Library с возможностью экспорта данных в XML файлы 430 Глава 19. Интерфейсы и компоненты Интерфейсы используются для описания общих протоколов классов, которые обычно не связываются через наследование. В данном решении удалось разделить вопросы хранения (отношение композиции), выдачи на время ( Borrowable) и экспортируемости (XMLEx portable). Интерфейсы использовались для определения общих прото колов классов, которые не должны быть связаны через наследование. 19.6. Порты Порт группирует семантически связанный набор предоставляемых и требуемых интерфейсов. Он указывает на конкретную точку взаимо действия классификатора и его окружения. Порт группирует семантически связанный набор предоставляемых и тре буемых интерфейсов. Пример на рис. 19.12 иллюстрирует нотацию порта. Здесь показан класс Book, имеющий порт presentation (представление). Этот порт со стоит из требуемого интерфейса DisplayMedium (устройство отображе ния) и предоставляемого интерфейса Display (отображение). Имя порта является необязательным. На рисунке показано два варианта нотации порта: слева – обычная, а справа – более краткий альтернативный ва риант. Однако эта альтернатива применима, только если у порта один тип предоставляемого интерфейса (у него по прежнему может быть нуль или более требуемых интерфейсов). Имя типа указывается после имени порта, как показано на рисунке. Порты являются очень удобным способом структурирования предо ставляемых и требуемых интерфейсов классификатора. Их также мож но использовать для упрощения диаграммы. Например, на рис. 19.13 показан класс Viewer (средство просмотра), соединяющийся с портом p resentation класса Book. Чтобы обеспечить возможность соединения портов, их предоставляемый и требуемый интерфейсы должны совпа дать. Использование портов, очевидно, обеспечивает намного более DisplayMedium Display Book presentation порт DisplayMedium Book presentation:Display имя порта тип порта Рис. 19.12. Два варианта нотации порта 19.7. Интерфейсы и компонентно ориентированная разработка 431 краткое представление, чем отображение всех предоставляемых и тре буемых интерфейсов, но может и усложнять чтение диаграмм. У портов может быть видимость. Когда порт изображается перекрыва ющим границу классификатора, он является открытым. Это означает, что предоставляемый и требуемый интерфейсы открытые (public). Ес ли прямоугольник порта находится внутри границы классификатора (как показано на рис. 19.14), видимость порта принимает два значе ния: или защищенный (protected) (по умолчанию), или закрытый (pri vate). Фактическая видимость графически не отображается, но запи сывается в спецификации порта. У порта может быть кратность. Ее указывают в квадратных скобках по сле имени порта и его типа (например, presentation:Display[1]). Кратность указывает на количество экземпляров порта, которые будут иметь эк земпляры классификатора. 19.7. Интерфейсы и компонентно ориентированная разработка Компонентно ориентированная разработка заключается в построении программного обеспечения из подключаемых частей. Интерфейсы – ключ к компонентно ориентированной разработке (com ponent based development, CBD). Она заключается в построении про граммного обеспечения из подключаемых частей. Если требуется соз дать гибкое, ориентированное на компоненты программное обеспече ние, для которого по желанию можно подключать новые реализации, при проектировании должны использоваться интерфейсы. Поскольку интерфейсы определяют только контракт, они обеспечивают возмож ность существования любого количества конкретных реализаций, подчиняющихся этому контракту. Book presentation:Display Viewer view Рис. 19.13. Соединение портов A aProtectedPort Рис. 19.14. Защищенный порт 432 Глава 19. Интерфейсы и компоненты В следующих разделах мы расскажем о компонентах, а затем обсудим, как можно сочетать компоненты и интерфейсы в CBD. 19.8. Что такое компонент? Спецификация UML 2.0 [UML2S] гласит: «Компонент представляет мо дульную часть системы, которая инкапсулирует ее содержимое, и ре ализация компонента замещаема в рамках его окружения». Компо нент как черный ящик, внешнее поведение которого полностью опре деляется его предоставляемыми и требуемыми интерфейсами. Поэто му один компонент может быть заменен другим, поддерживающим тот же протокол. Компонент – модульная и замещаемая часть системы, инкапсулирующая ее содержимое. Компоненты могут иметь атрибуты и операции и участвовать в отно шениях ассоциации и обобщения. Компоненты – это структурирован ные классификаторы. У них может быть внутренняя структура, вклю чающая части и соединители. Структурированные классификаторы рассматривались в разделе 18.12.1. Если вы до сих пор не ознакоми лись с ними, рекомендуем сделать это сейчас, прежде чем двигаться дальше. Компоненты могут представлять что то, экземпляр чего может быть создан во время выполнения, например EJB (Enterprise JavaBean). Или ими может быть представлена абсолютно логическая конструк ция, такая как подсистема, экземпляры которой создаются только косвенно через создание экземпляров ее частей. Компонент может быть представлен одним или более артефактами. Артефакт представляет некоторую физическую сущность, например исходный файл. В частности, компонент EJB мог бы быть представлен файлом JAR (Java Archive – Java архив). Более подробно артефакты обсуждаются в разделе 24.5. На диаграмме компонентов могут быть показаны компоненты, зависи мости между ними и то, как компонентам назначаются классификато ры. Компонент отображается в виде прямоугольника со стереотипом «component» (компонент) и/или пиктограммой компонента в верхнем правом углу, как на рис. 19.15. У компонентов могут быть предостав ляемые и требуемые интерфейсы и порты. Компонент может иметь внутреннюю структуру. Части можно пока зать вложенными внутрь компонента (рис. 19.16) или находящимися снаружи и соединенными с ним отношением зависимости. Обе формы синтаксически эквивалентны, хотя первая нотация нам кажется более наглядной. |