Главная страница
Навигация по странице:

  • Контрольные вопросы

  • Как класс изображается на диаграмме UML

  • Рис. 3.1. А что внутри

  • Символ Значение

  • Как использовать объекты класса

  • Всегда ли нужно создавать новые классы

  • ВВедение в ИМЛ. Для чего был написан этот курс


    Скачать 3.44 Mb.
    НазваниеДля чего был написан этот курс
    АнкорВВедение в ИМЛ
    Дата10.03.2023
    Размер3.44 Mb.
    Формат файлаpdf
    Имя файлаvvedenie_v_UML.pdf
    ТипДокументы
    #978344
    страница5 из 15
    1   2   3   4   5   6   7   8   9   ...   15
    абстрагироваться от несущественных свойств системы. В этом плане очень полезными могут оказаться коллективные упражнения на выявление и анализ прецедентов. Они помогут отработать навыки выявления четких абстракций.
    Неплохой способ начать - моделирование базовых абстракций или поведения одной из уже
    имеющихся у вас систем.
    Стройте модели предметной области задачи в виде диаграммы классов! Это хороший способ понять, как визуализировать множества взаимосвязанных абстракций. Таким же образом стройте модели статической части задач.

    Моделируйте динамическую часть задачи с помощью простых диаграмм последовательностей
    и кооперации. Хорошо начать с модели взаимодействия пользователя с системой - так вы сможете легко выделить наиболее важные прецеденты.
    Не забываем, что мы говорим, прежде всего, именно об объектноориентированных системах.
    Поэтому, подытоживая все сказанное ранее, можно предложить такую последовательность построения диаграмм:

    диаграмма прецедентов,
    • диаграмма классов,

    диаграмма объектов,
    • диаграмма последовательностей,
    • диаграмма кооперации,
    • диаграмма состояний,

    диаграмма активности,

    диаграмма развертывания.
    Конечно, это не единственная возможная последовательность. Возможно, вам будет удобнее начать с диаграммы классов. А может, вам не нужны диаграммы объектов, а диаграммы последовательностей вы предпочитаете диаграммам кооперации. Это лишь один из путей, постепенно вы выработаете свой персональный стиль проектирования и свою последовательность!
    И напоследок еще несколько советов относительно использования UML.
    Хорошее и полезное упражнение - строить модели классов и отношений между ними для уже написанного вами кода на С++ или Java.
    Применяйте UML для того, чтобы прояснить неявные детали реализации существующей системы или использованные в ней "хитрые механизмы программирования".
    Стройте UML-модели, прежде чем начать новый проект. Только когда будете абсолютно удовлетворены полученным результатом, начинайте использовать их как основу для кодирования.
    Обратите особое внимание на средства UML для моделирования компонентов, параллельности, распределенности, паттернов проектирования. Большинство из этих вопросов мы рассмотрим далее.
    UML содержит некоторые средства расширения. Подумайте, как можно приспособить язык к предметной области вашей задачи. И не слишком увлекайтесь обилием средств UML: если вы в каждой диаграмме будете использовать абсолютно все средства UML, прочесть созданную вами модель смогут лишь самые опытные пользователи.
    Кроме прочего, важным моментом здесь является выбор пакета UML-моделирования (CASE- средства), что тоже может повлиять на ваш индивидуальный стиль проектирования. Более подробно мы поговорим об этом в одной из последующих лекций, пока же отметим, что все диаграммы, виденные вами в этой лекции, построены с помощью TAU G2 от Telelogic.
    Выводы


    Диаграммы разных видов позволяют взглянуть на систему с разных точек зрения.

    UML содержит диаграммы трех типов - для моделирования статической структуры, поведенческих аспектов и подробностей реализации приложения.

    Недостаточно читать об UML - им надо пользоваться!
    Контрольные вопросы

    Почему нужно строить разные диаграммы при моделировании системы?

    Какие диаграммы соответствуют статическому представлению о системе?

    Вы разрабатываете компьютерную программу для игры в шахматы. Какая диаграмма UML была бы полезной в этом случае? Почему?

    Составьте список вопросов потенциальному пользователю такой программы. Объясните, почему вы хотели бы задать именно их.
    Рис. 2.4.
    Из всего сказанного выше становится понятно, что диаграммы прецедентов относятся к той группе диаграмм, которые представляют динамические или поведенческие аспекты системы. Это отличное средство для достижения взаимопонимания между разработчиками, экспертами и
    конечными пользователями продукта. Как мы уже могли убедиться, такие диаграммы очень просты для понимания и могут восприниматься и, что немаловажно, обсуждаться людьми, не являющимися специалистами в области разработки ПО.

    Подводя итоги, можно выделить такие цели создания диаграмм прецедентов:
    • определение границы и контекста моделируемой предметной области на ранних этапах проектирования;
    • формирование общих требований к поведению проектируемой системы;
    • разработка концептуальной модели системы для ее последующей детализации;
    • подготовка документации для взаимодействия с заказчиками и пользователями системы.

    Лекция 4: Диаграмма классов: крупным планом
    Аннотация: Диаграмма классов - один из наиболее часто используемых видов диаграмм UML.
    Обычно создание диаграммы классов знаменует собой окончание процесса анализа и начало процесса проектирования. Мы уже встречались с ними в лекции "Виды диаграмм", а теперь изучим их более внимательно. В этой лекции мы рассмотрим такие вопросы: как класс изображается на диаграмме UML; а что внутри; как использовать объекты класса; всегда ли нужно создавать новые классы; отношения между классами
    Как класс изображается на диаграмме UML?
    Архитектор программного обеспечения в первую очередь обращает внимание на объекты предметной области. Программист же концентрируется на поведении этих объектов, пользуясь классами, к которым они принадлежат. Вот поэтому-то диаграмма классов и является одной из важнейших диаграмм UML. Она используется для документирования программных систем, и основным ее компонентом является класс. Что такое класс, мы уже говорили ранее, когда знакомились с видами диаграмм UML. В предыдущей лекции мы рассматривали назначение диаграммы классов, знакомились с примерами готовых диаграмм, но не вникали в тонкости обозначений, используемых на диаграмме. В тех примерах все казалось нам очень понятным и логичным. Тем не менее, некоторые нюансы все же следует рассмотреть, и как раз этим мы сейчас и займемся.
    Класс на диаграмме изображается в виде прямоугольника, разделенного горизонтальными линиями на три части. В первой части указывается название класса. Как правило, имя
    класса состоит из одного, максимум двух слов. Вторая часть содержит перечень атрибутов класса, которые характеризуют тот или иной объект этого класса в модели предметной области. Третья часть содержит перечень операций, отражающих его поведение в модели предметной
    области (
    рис. 3.1
    ). Все очень просто, не так ли?
    Рис. 3.1.
    А что внутри?
    Мы узнали, как класс изображается и выглядит "снаружи". А что же внутри объектов класса?
    Пользователю об этом знать необязательно, более того, абсолютно не нужно. Для человека, использующего его, объект выступает в роли черного ящика. Скрывая от пользователя внутреннее устройство объекта, мы обеспечиваем его надежную работу. Сейчас мы рассмотрим, как убрать из поля зрения пользователя то, что ему знать не нужно.
    Читателя может слегка смутить слово "пользователь", которым мы злоупотребляли в предыдущем абзаце. Зачем вообще пользователю какие-то объекты и классы? Внесем ясность.
    Программист, использующий в своей программе созданные кем-то компоненты, как раз и
    выступает в роли такого пользователя. Зачем ему знать что внутри - он знает, какие атрибуты надо модифицировать и какие операции использовать, чтобы заставить объект работать именно так, как ему нужно! Более того, а многие ли из нас знают, как именно устроен и по каким принципам работает, например, телевизор - объект класса "Бытовой прибор"?
    Сокрытие от пользователя внутреннего устройства объектов называется инкапсуляцией. Если говорить более "научным" языком, то инкапсуляция - это защита отдельных элементов объекта, не затрагивающих существенных характеристик его как целого. Инкапсуляция нужна не только для того, чтобы создать иллюзию простоты объекта для пользователя (по словам Г. Буча). Но вернемся к примеру с телевизором. Нам этот прибор кажется очень простым только потому, что при работе с ним мы используем простой и понятный интерфейс - пульт дистанционного управления. Мы знаем: для того чтобы увеличить громкость звука, надо нажать вот эту кнопку, а чтобы переключить канал - вот эту. Как телевизор устроен внутри, мы не знаем. Более того - в отсутствие пульта ДУ такое знание было бы неудобным для нас и весьма опасным для самого телевизора, вздумай мы увеличить громкость с помощью паяльника. Поэтому-то пульт ДУ и защищает от нас "внутренности" телевизора! Вот так инкапсуляция реализуется в реальном мире.
    В программировании инкапсуляция обеспечивается немного по-другому - с помощью т. н. модификаторов видимости. С их помощью можно ограничить доступ к атрибутам и операциям объекта со стороны других объектов. Звучит это немного пугающе, но на самом деле все просто. Если атрибут или операция описаны с модификатором private, то доступ к ним можно получить только из операции, определенной в том же классе. Если же атрибут или операция описаны с модификатором видимости public, то к ним можно получить доступ из любой части программы. Модификатор protected разрешает доступ только из операций этого же класса и классов, создаваемых на его основе. В языках программирования могут встречаться модификаторы видимости, ограничивающие доступ на более высоком уровне, например, к классам или их группам, однако смысл инкапсуляции от этого не изменяется.
    В UML атрибуты и операции с модификаторами доступа обозначаются специальными символами слева от их имен:
    Символ Значение
    + public - открытый доступ
    - private - только из операций того же класса
    # protected - только из операций этого же класса и классов, создаваемых на его основе
    Рассмотренный ранее пример с телевизором средствами UML (конечно же, это очень высокоуровневая абстракция) можно изобразить так (
    рис. 3.2
    ):

    Рис. 3.2.
    Не правда ли, все понятно и предельно просто? Зачем, например, пользователю знать числовые значения частот каналов? Он знает, что достаточно запустить процедуру автоматического поиска каналов и телевизор все сделает за него. Вот вам и инкапсуляция - оказывается, она повсюду вокруг нас. Оглянитесь и подумайте, сколько вещей вокруг имеют скрытые свойства и выполняют скрытые операции. Испугались? Вот то-то же!
    Как использовать объекты класса?
    Итак, мы рассмотрели инкапсуляцию - одно из средств защиты объектов. Все вроде бы понятно, но как же именно работать с объектом?
    Если уж говорить о защите объекта, то чтобы она действительно была эффективной, надо позаботиться о некоем стандартном и безопасном, не зависящим от языка программирования способе доступа к объекту. К тому же такой стандартный способ доступа должен быть простым и с точки зрения использования, и с точки зрения реализации. Вспомните пример с телевизором.
    Нажимая кнопки на пульте, мы ожидаем, что телевизор откликнется на это действие каким-то определенным образом - именно так, как мы ожидаем, а не иначе. То есть, с одной стороны, пульт ДУ является средством доступа к скрытым операциям, выполняемым телевизором, а с другой стороны - пульт обеспечивает нужное для нас поведение телевизора. В данном примере именно пульт является таким стандартным средством доступа к телевизору. Можно даже сказать, средством доступа, не зависящим от конкретной модели телевизора - вспомните об универсальных пультах и о том, как отключаете звук надоедливой рекламы на экране в вагоне поезда, используя КПК!
    В том же примере с телевизором у нас впервые промелькнуло слово интерфейс. И не случайно промелькнуло: именно так называют тот самый стандартный способ доступа к объекту. Более строго, интерфейс - это логическая группа открытых ( public ) операций объекта. Один и тот же объект может иметь несколько интерфейсов. У телевизора, например, их два - пульт ДУ и кнопки на корпусе. А может и больше - вспомните о возможности управлять бытовой техникой с помощью КПК или универсального пульта ДУ.
    Кстати, посмотрите внимательнее на пульт ДУ или на экран программы удаленного контроля. Что вы видите - кнопки? Или кнопки, сгруппированные по функциональному признаку? Да, именно так: кнопки, переключающие каналы, расположены отдельно, рядом - группа кнопок, отвечающих за регулировку громкости звука, рядом - группа программируемых кнопок, и т. д. В принципе, можно сказать, что пульт реализует не один, а несколько интерфейсов - по числу функциональных групп кнопок. Впрочем, это уже формализм: мы просто хотели проиллюстрировать слова "логическая группа" в определении интерфейса.
    Однако интерфейс - это не только и не столько группа операций объекта. Интерфейс отражает внешние проявления объекта, показывает, каким образом осуществляется взаимодействие с ним, скрывая остальные детали, не имеющие отношения к процессу взаимодействия.
    Интерфейс всегда реализуется некоторым классом, который в таком случае называют классом, поддерживающим интерфейс. Как мы уже говорили ранее, один и тот же объект может иметь несколько интерфейсов. Это означает, что класс этого объекта реализует все операции этих интерфейсов. К данному моменту в голове читателя может созреть вопрос: "Мы же, вроде бы, говорили о классах и объектах, а теперь вдруг перешли на интерфейсы. Да и вообще, используются ли они в практике программирования или являются просто изящной теоретической конструкцией?". Ответ на этот вопрос прост: многие из существующих технологий
    программирования (например, COM, CORBA, Java Beans) не только активно используют механизм
    интерфейсов, но и, по сути, полностью основаны на нем.
    Что ж, наверное, пришло время поговорить о том, как интерфейс изображается на диаграммах.
    Изображаться он может несколькими способами. Первый и самый простой из них - это класс со стереотипом <> (
    рис. 3.3
    ):
    Рис. 3.3.
    Этот способ хорош, если нужно показать, какие именно операции предоставляет интерфейс. Если же такие подробности в данный момент не важны, предоставляемый интерфейс изображают в виде кружочка или, как говорят, "леденца" ( lollipop ) (
    рис. 3.4
    ):
    Рис. 3.4.
    Обратите внимание на маленький значок на закладке папки ConduitSet. Это обозначение подсистемы, мы могли бы не рисовать его, а просто использовать стереотип <>.
    Впрочем, об этом мы еще поговорим.
    И наконец, еще один способ изображения интерфейса. Он не является альтернативой описанным ранее способам, а используется для изображения интерфейсов, требующихся объекту для выполнения его работы. Обозначается он очень простым и логичным символом. Впрочем, судите сами (
    рис. 3.5
    ):
    Рис. 3.5.
    Наблюдательный читатель уже, наверное, заметил, как логически совмещаются символы предоставляемого и требуемого интерфейсов.
    Действительно, на диаграммах довольно часто можно увидеть такую картинку (
    рис. 3.6
    ):
    Рис. 3.6.

    Да, кстати, вы заметили, что названия интерфейсов начинаются с буквы I? Эта традиция пошла из языка Java, и, как показывает практика, она весьма облегчает жизнь, если нужно, например, быстро разобраться в сложной диаграмме, составленной другим человеком.
    Всегда ли нужно создавать новые классы?
    Начнем с вопроса, казалось бы, не имеющего никакого отношения к рассматриваемому вопросу, а именно - всегда ли нужно создавать новый класс для каждой новой задачи? Правильный ответ, конечно же, "нет". Это было бы странно и неэффективно. "Фишка" состоит в том, что мы можем использовать уже существующие классы, адаптируя их функциональность для выполнения новых задач. Таким образом появляется возможность не создавать систему классов с нуля, а задействовать уже имеющиеся решения, которые были созданы ранее, при работе над предыдущими проектами. Впрочем, наше высказывание о странности и неэффективности создания новых классов не является истиной в последней инстанции. Могут быть ситуации, когда существующие классы по каким-либо причинам не устраивают архитектора, и тогда требуется создать новый класс. Следует, однако, избегать ситуаций, когда созданный класс (а точнее, его набор операций и атрибутов) практически повторяет существующий, лишь незначительно отличаясь от него. Все-таки лучше не изобретать велосипед и стараться создавать классы на основе уже существующих, и только если подходящих классов не нашлось - создавать свои, которые, в свою очередь, могут (и должны!) служить основой для других классов. Мы уже не говорим о том, что создание классов предполагает значительный объем усилий по кодированию и тестированию. В общем случае, сказанное выше можно проиллюстрировать такой диаграммой
    (
    рис. 3.7
    ):
    Рис. 3.7.
    В дополнение можно назвать несколько причин, почему стоит использовать уже существующие классы:
    Во-первых, идя этим путем, мы пользуемся плодами ранее принятых решений. Действительно, если когда-то мы уже решили некоторую проблему, зачем начинать все "с нуля", повторяя уже однажды проделанные действия?
    Во-вторых, таким образом мы делаем решение мобильным и расширяемым. Используя уже существующие классы и создавая на их основе новые, мы можем развивать решение практически неограниченно, добавляя лишь необходимые нам в данный момент детали - атрибуты и операции.

    В-третьих, существующие классы, как правило, хорошо отлажены и показали себя в работе.
    Разработчику не надо тратить время на кодирование, отладку, тестирование и т. д., - мы работаем с хорошо отлаженным и проверенным временем кодом, который зарекомендовал себя в других проектах и в котором уже выявлено и исправлено большинство ошибок.
    А теперь внимание - мы много говорили о том, что нужно создавать классы на основе уже существующих, но так и не сказали ни слова о том, как это сделать. Пришло время внести ясность в этот вопрос. Тем самым мы подбираемся к понятию
    1   2   3   4   5   6   7   8   9   ...   15


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