- •4. Объектно-ориентированное проектирование, основы uml
- •4.1 Значение моделирования
- •4.2 Принципы моделирования
- •4.3 Объектное моделирование
- •4.4 Принципы моделирования с использованием uml
- •4.5 Основные диаграммы языка uml
- •4.6 Сущности uml
- •4.7 Отношения uml
- •5. Диаграмма классов и моделирование предметной области
- •5.1 Общие сведения
- •5.2 Класс
- •5.3 Имя класса
- •5.4 Атрибуты класса
- •5.5 Операции класса
- •5.6 Отношения между классами
- •5.7 Отношение зависимости
- •5.8 Зависимость между пакетами
- •5.9 Отношение ассоциации
- •5.10 Отношение агрегации
- •5.11 Отношение композиции
- •5.12 Отношение обобщения
- •5.13 Рекомендации по построению диаграммы классов
- •6. Диаграмма состояний
- •6.1 Общие сведения
- •6.2 Автоматы
- •6.3 Состояние
- •6.4 Начальное и конечное состояния
- •6.5 Переход
- •6.6. Составное состояние и подсостояние
- •6.7. Параллельные подсостояния
- •6.8 Рекомендации
- •7 Диаграмма деятельности
- •7.1 Общие сведения
- •7.2 Состояние действия и состояние деятельности
- •7.3 Переход
- •7.4 Ветвление
- •7.5. Разделение и слияние
- •7.6 Дорожки
- •7.7. Объекты
- •7.8. Рекомендации по построению диаграмм деятельности
- •8. Моделирование взаимодействия объектов. Диаграммы последовательности и кооперации (коммуникации)
- •8.1 Диаграмма последовательности, общие сведения
- •8.2 Объекты
- •8.3 Линия жизни объекта
- •8.4 Фокус управления
- •8.5 Сообщения
- •8.6 Ветвление потока управления
- •8.7 Стереотипы сообщений
- •8.8 Временные ограничения
- •8.9 Пример построения диаграммы последовательности
- •8.10. Рекомендации по построению диаграмм последовательности
- •8.11 Общие сведения о диаграмме кооперации (коммуникации)
- •8.12 Кооперация
- •8.13 Объекты
- •8.14 Мультиобъекты
- •8.15. Активные объекты
5.8 Зависимость между пакетами
Зависимости можно устанавливать не только между классами, но и между пакетами. Фактически, это единственный тип связей, существующий между пакетами. Как и в случае классов, зависимость между пакетами изображают пунктирной линией.
Отношение зависимости между пакетами А и В означает, что некоторый класс пакета А связан однонаправленным отношением с некоторым классом пакета В. Иначе говоря, класс из пакета А должен знать что-либо о классе из пакета В.
Зависимости определяют возможность повторного использования пакетов. Зависимость пакета А от пакета В означает, что при создании других приложений пакет А можно использовать только совместно с пакетом В. Однако сам пакет В можно использовать повторно, так как он не зависит ни от чего больше.
Зависимости между пакетами можно обнаружить, исследуя отношения на диаграмме классов. Если два класса из различных пакетов связаны, эти пакеты также связаны.
Создавая зависимости между пакетами, старайтесь по мере возможности избегать циклических зависимостей. Такая зависимость предполагает, что класс из пакета А должен знать о классе из пакета В, а еще какой-то класс пакета В должен знать о классе из пакета А. Следовательно, ни один пакет нельзя самостоятельно использовать повторно, и изменения в одном из них неизбежно повлияют на другой. Таким образом, теряется одно из преимуществ пакетов - они становятся слишком взаимозависимы.
Чтобы разбить циклическую зависимость, разделите пакет на два. В нашем примере можно взять классы пакета В, от которых зависит А, и переместить их в третий пакет С. Тогда зависимости пакетов будут выглядеть так, как показано на рис. 5.6.
Рисунок 5.6. Зависимость между пакетами.
5.9 Отношение ассоциации
Отношение ассоциации соответствует наличию некоторого отношения между классами. Данное отношение обозначается сплошной линией с дополнительными специальными символами, которые характеризуют отдельные свойства конкретной ассоциации. В качестве дополнительных специальных символов могут использоваться имя ассоциации, а также имена и кратность классов-ролей ассоциации. Имя ассоциации является необязательным элементом ее обозначения. Если оно задано, то записывается с заглавной (большой) буквы рядом с линией соответствующей ассоциации.
Наиболее простой случай данного отношения — бинарная ассоциация. Она связывает в точности два класса и, как исключение, может связывать класс с самим собой. Для бинарной ассоциации на диаграмме может быть указан порядок следования классов с использованием треугольника в форме стрелки рядом с именем данной ассоциации. Отсутствие данной стрелки рядом с именем ассоциации означает, что порядок следования классов в рассматриваемом отношении не определен.
В качестве простого примера отношения бинарной ассоциации рассмотрим отношение между двумя классами — классом "Компания" и классом "Сотрудник" , как показано на рис. 5.7. Они связаны между собой бинарной ассоциацией Работа, имя которой указано на рисунке рядом с линией ассоциации. Для данного отношения определен порядок следования классов, первым из которых является класс "Сотрудник", а вторым — класс "Компания". Отдельным примером или экземпляром данного отношения может являться пара значений (Петров И. И., "Сиеста-металл"). Это означает, что сотрудник Петров И. И. работает в компании "Сиеста-металл".
Рисунок 5.7. Графическое изображение отношения бинарной ассоциации между классами
Одним из таких дополнительных обозначений является имя роли отдельного класса, входящего в ассоциацию. Имя роли представляет собой строку текста рядом с концом ассоциации для соответствующего класса. Она указывает специфическую роль, которую играет класс, являющийся концом рассматриваемой ассоциации. Имя роли не является обязательным элементом обозначений и может отсутствовать на диаграмме.
Кратность отдельного класса обозначается в виде интервала целых чисел, аналогично кратности атрибутов и операций классов. Интервал записывается рядом с концом ассоциации и для N-арной ассоциации означает потенциальное число отдельных экземпляров или значений кортежей этой ассоциации, которые могут иметь место, когда остальные N-1 экземпляров или значений классов фиксированы.
Так, для рассмотренного примера, приведенного на рис. 5.7 кратность "1" для класса "Компания" означает, что каждый сотрудник может работать только в одной компании. Кратность "1..*" для класса "Сотрудник" означает, что в каждой компании могут работать несколько сотрудников, общее число которых заранее неизвестно и ничем не ограничено. Заметим, что вместо кратности "1..*" записать только символ "*" нельзя, поскольку последний означает кратность "0..*". Для данного примера это означало бы, что отдельные компании могут совсем не иметь сотрудников в своем штате.
Что касается других свойств отношения, ассоциации, то в случае их наличия, они могут рассматриваться в качестве атрибутов класса ассоциации и могут быть указаны на диаграмме обычным для класса способом в соответствующей секции прямоугольника класса.
Частным случаем отношения ассоциации является так называемая исключающая ассоциация (Xor-association). Семантика данной ассоциации указывает на тот факт, что из нескольких потенциально возможных вариантов данной ассоциации в каждый момент времени может использоваться только один ее экземпляр. На диаграмме классов исключающая ассоциация изображается пунктирной линией, соединяющей две и более ассоциации, рядом с которой записывается строка-ограничение "{Xor}".
Например, счет в банке может быть открыт для клиента, в качестве которого может выступать физическое или юридическое лицо, что изображается с помощью исключающей ассоциации на рис. 5.8.
Рисунок 5.8. Графическое изображение исключающей ассоциации между тремя классами
Специальной формой или частным случаем отношения ассоциации является отношение агрегации, которое, в свою очередь, тоже имеет специальную форму — отношение композиции. Поскольку эти отношения имеют свои специальные обозначения и относятся к базовым понятиям языка UML, рассмотрим их последовательно.
С точки зрения кодогенерации наличие на диаграмме отношения ассоциации указывает на возможность одного класса узнавать об общих атрибутах и операциях другого класса. Например, на рис. 5.9 показана двунаправленная ассоциация между классами Дом и Жилец.
Класс Жилец знает об общих атрибутах и операциях Дома, а Дом - об общих атрибутах и операциях Жильца. Таким образом, на диаграммах последовательности Дом может посылать сообщения Жильцу, и наоборот.
Рисунок 5.9 Двунаправленная ассоциация между классами Дом и Жилец: классы могут обмениваться сообщениями
В приведенном примере отношение ассоциации - двунаправленное. Однако ассоциации можно сделать и однонаправленными. Такими отношениями легче управлять, и проще обнаружить классы, допускающие повторное использование. На рис. 5.10 показана однонаправленная ассоциация.
Рисунок 5.10. Ассоциация, направленная от класса Жилец к классу Дом.
В этом случае Жилец знает об общих атрибутах и операциях Дома, но Дом не знает об атрибутах и операциях Жильца. Сообщения на диаграммах последовательности и кооперации могут отправляться Жильцом и приниматься Домом, но не наоборот.
Направление ассоциации можно определить, изучая диаграммы последовательности и кооперации. Если все сообщения на них отправляются только Жильцом и принимаются только Домом, но не наоборот, между этими классами существует однонаправленное отношение ассоциации. Если хотя бы одно сообщение идет в обратную сторону, ассоциация должна быть двунаправленной.
Однонаправленные отношения позволяют выявить классы, являющиеся кандидатами на повторное использование. Если ассоциация двунаправленная, каждый класс-участник должен знать о другом, и ни один из них не может применяться без другого. Так Жилец должен знать о Доме и потому не может использоваться без него. Однако Дом не должен знать о Жильце и потому допускает самостоятельное повторное использование. Класс с большим количеством исходящих однонаправленных связей повторно использовать трудно, а класс, все связи которого входящие - чрезвычайно легко.
При генерации кода для двунаправленной ассоциации создаются дополнительные атрибуты у каждого класса. В нашем примере атрибут класса Жилец будет помещен внутри Дома, а атрибут класса Дом внутри Жильца. Ниже приведен код на Java, сгенерированный для этих двух классов.
Программный код для класса Жилец:
public class Person
{
public House m_House;
public Person() {}
}
Программный код для класса Дом:
public class House
{
public Person m_Person;
public House() {}
}
В случае однонаправленной ассоциации атрибут Дом будет помещен внутри Жильца, но не наоборот. Ниже приведен код для однонаправленной ассоциации.
Программный код для класса Жилец:
public class Person
{
public House m_House;
public Person() {}
}
Программный код для класса Дом:
public class House
{
public House() {}
}
Ассоциации могут быть рефлексивными. Рефлексивная ассоциация предполагает, что один экземпляр класса взаимодействует с другими экземплярами этого же класса. Рассмотрим класс Жилец.
Один человек может быть родителем нескольких других людей. Поскольку все они являются взаимодействующими друг с другом экземплярами класса Жилец, мы получаем рефлексивную ассоциацию.
Для отношения "один к одному" кодогенераторы обычно создают атрибуты, необходимые для поддержки ассоциации: в одном классе должен содержаться набор элементов другого класса. Рассмотрим пример, приведенный на рис. 5.11.
Рисунок 5.11. Ненаправленная ассоциация, роли классов в которой сгенерированы по умолчанию.
Программный код, генерируемый для приведенного отношения, имеет следующий вид.
Программный код для Class_A:
public class Class_A
{
public Class_B theClass_B[];
public Class_A() {}
}
Программный код для Class_B:
public class Class_B
{
public Class_A theClass_A;
public Class_B() {}
}
Здесь в классе Class_B просто содержится атрибут, имеющий тип Class_A. Но поскольку множественность говорит о том, что каждому экземпляру класса Class_А соответствует несколько экземпляров класса Class_B, то внутри класса Class_A создается массив объектов класса Class_B.