Pull to refresh

UML, Классы и Отношения

Website development *UML Design *
Существует много разработанных теорий, задокументированных технологий и парадигм программирования. Перед тем как углубиться с головой в их изучение было бы мудро изучить сам принцип взаимодействия программ и их структур. UML предлагаем вам разработанный стандарт что бы сделать это.



Эту статью я бы хотел посвятить одному из небольших разделов UML — диаграмме классов (class diagrams)
Перед изучением автор советует иметь под рукой UML редактор или «поиметь» сейчас один из след UML редакторов:
думаю они уже были разобраны вот в этой статье habrahabr.ru/blogs/webdev/42812

Эта статья не вдается во все тонкости UML, она посвящена базовым навыкам, таким как понимание связей и отношений классов или других структур данных

Что такое диаграммы классов?
Понятие класса диаграммы представляет собой описание сущности и его отношений. Сущность в большинстве случает представляет класс или интерфейс который содержится в вашем коде, но иногда сущность может ссылаться на более абстрактные объекты или даже на типы данных

Представление Классов



все очень просто:
Вверху пишется имя класса
Средняя часть компонента представлена в виде свойств, ссылок и атрибутов
Нижняя часть компоненты представлена в виде операций которые в большинстве случаев соответствуют методам в коде, подчёркнутые операции означают статическую операцию



Названия абстрактных классов будет выделено курсивом

Интерфейсы представлены идентично по отношению к классам за исключением того что в название будет добавлено ключевое слово
< >



Пакеты
Пакет это сущность которая представляет собой группу классов и интерфейсов. В основах UML пакет представлен в след виде:



Типы данных
Типы данных — это тоже сущности, но за исключением классов они не могут быть представлены отдельно в диаграмме классов — они всегда связанны с атрибутом, принадлежат входным аргументам или возвращающим значением.



Представление различных типов видимости данных в UML
+ public
# protected
— private
~ package

UML не ограничена только виденьем членов класса — сам класс может иметь своё виденье тоже. Если вы хотите посмотреть «на всю картину» вам нужно использовать пакетную диаграмму.

Отношения


Последовательное представление отношений сущностей очень полезно. Самая главная часть диаграммы классов — это отношение.
Ниже представлены всех отношения которые мы будем рассматривать:
Associations
Bi-directional asociation (standart association)
Uni-directional association
Associationo class (drop class)
Aggregation
Regular aggregation
Composition (composite aggregation)
Generalizations
Dependencies


Assocations


Assocations — это отношение между двумя классификаторами, описывающее связь между их экземплярами. Ассоциации имеют навигацию, показывая отношение одного класса к другому. Каждая сущность вовлечённая в эту связь выполняет определённую роль, роли могут быть назначены.
Так же здесь могут быть разные отношения между сущностями:
0..1 ноль или один
1 только один
0..* ноль или много
1..* один или много
n Только n (где n > 1)
0..n ноль к n (где n > 1)
1...n один к n (где n > 1)



все эти параметры опциональные, но если вы их укажете, в дальнейшем может значительно улучшить читабельность диаграммы.
Если связь не указана то по умолчанию использует 1 к 1

Bi-directional naviageble association

Bi-directional подразумевает что оба класса осведомлены о свой зависимости к другому классу. Давайте рассмотрим диаграмму



Этот пример показывает что оба класса ShoppingCart и Customer осведомлены о существовании друг друга и таким образом взаимодействуют. Хотя ShoppingCart относиться к Customer и наоборот, они оба могут быть частью чего-то большего.

Обратите внимание на множественное отношение, в примере у покупателя может быть несколько покупательских тележек.
Давайте рассмотрим код приведенной выше диаграммы:

  1. class Customer 
  2. { 
  3.   public function getCheckOutDetails(ShoppingCart $cart) 
  4.   { 
  5.     $this->checkCredit( 
  6.       $cart->getAmount() 
  7.     ); 
  8.     //. 
  9.   } 
 10. } 
 11. 
 12. class ShoppingCart 
 13. { 
 14.   public function checkOutUsingCustomer(Customer $customer) 
 15.   { 
 16.     $customer->getCheckOutDetails($this); 
 17.     //. 
 18.   } 
 19. } 


* This source code was highlighted with Source Code Highlighter.


итак нам нужно запомнить что оба класса знают о существовании друг друга

Uni-direction navigable association

в Uni-direction отношении только один класс осведомлён о существовании другого


В этом примере, класс ShoppingCart ничего не знает об классе Customer, но! Customer осведомлен о ShoppingCart и в этом проявляется их отношение. Отметьте что мы оставили множественное значение, подчеркивая что класс Customer знает об множестве ShoppingCart, в то время как само множество ShoppingCart ничего не знает об классе Customer.

Для общности картины, отношение Customer to ShoppingCart может быть диагонально перевернуто, и тогда мы получим вот такую схему:


сейчас единственный класс ShoppingCart относиться ко множеству Customer, без их «виденья». Думаю этот пример Uni-directional должен быть вам знакомым

дайте рассмотрим сам код:

  1. class Customer 
  2. { 
  3.   public function getCreditDetails($purchaseAmount) 
  4.   { 
  5.     $this->checkCredit($purchaseAmount); 
  6.     //. 
  7.     
  8.   } 
  9. } 
 10. 
 11. class ShoppingCart 
 12. { 
 13.   public function checkOutUsingCustomer(Customer $customer) 
 14.   { 
 15.     $customer->getCheckOutDetails($this->getAmount()); 
 16.     //. 
 17.   } 
 18. } 


* This source code was highlighted with Source Code Highlighter.


Association class:



Класс ассоциаций, или drop class это класс который показывает специфическую ассоциацию:



пунктирная линия в примере показывает нам что сущность Customer относиться к сущности ShoppingCart и при этом существует сущность WishList, те отношение между Customer и ShoppingCart зависит от существования WishList.

Drop class может принимать любое отношение, включая агрегированную ассоциацию (см след параграф) с любой навигацией.
Круг на зарисовке — опционален.

По традиции, конечно пример кода:

  1. class Customer 
  2. { 
  3.   public function checkoutCart(ShoppingCart $cart) 
  4.   { 
  5.     $cart->getItems(); 
  6.     //. 
  7.     return $items; 
  8.     
  9.   } 
 10. } 
 11. 
 12. class ShoppingCart 
 13. { 
 14.   public function getItems() 
 15.   { 
 16.     //. 
 17.   } 
 18. } 
 19. 
 20. class WhishList 
 21. { 
 22.   public function makeCheckOutList(Customer $customer, ShoppingCart $cart) 
 23.   { 
 24.     $this->updateWhishList( 
 25.       $customer->checkoutCart($cart) 
 26.     ); 
 27.     //. 
 28.   } 
 29. } 


* This source code was highlighted with Source Code Highlighter.


Aggregation (aggregate association)



Агрегирование — показывает что одна сущность является частью другой. Если говорить на простом программерском языке, то это означает что экземпляр сущности наследуется другим через свойства объекта.

Regular aggregation
В обычом агрегированнии цикл жизни сущности зависит от цикла жизни сущностей его образовавших, это и состовляет их отношение. Отмете что ромбообразная форма у края указывает на образующию сущность.

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



Один экземпляр Customer наследует один экземпляр ShoppingCart, в роли currentCart. Однако, Customer
получает существующий объкт ShoppingCart, создавая тем самым зависимость экзепляра ShoppingCart от экземпляра Customer.

давайте рассмотрим код:

  1. class Customer 
  2. { 
  3.   private $_cart; 
  4.   
  5.   public function __construct(ShoppingCart $cart) 
  6.   { 
  7.     $this->_cart = $cart;     
  8.   } 
  9. } 
 10. 
 11. class ShoppingCart 
 12. { 
 13.   
 14. } 


* This source code was highlighted with Source Code Highlighter.


Composite Aggregagtion (composition)



В композитивном агрегированнии сам объкт это композиция частей других объектов чей жизненый цикл зависит от жизни самой композиции.
Здесь должна быть строгая связь, в которой целое это композиция его частей:
1. У машины есть колёса, но 4 колеса не состовляют машину
2. Mysql Кластер это композиции mysql серверов, но сам по себе mysql сервер не представляет кластер.

как видно из 2-го примера — у нас должна быть довольно строгая связь. Пользуясь этой связью давай приведем еще один пример:
США это композиция ее штатов:
Возможно все штаты америки не равны США, но здесь мы имеем строгую связь которую требует Composite Aggregation:
США не может сущестовать без своих штатов, машина не может выполнять свои функции без колес, а покупатель не существует без покупательской тележки.

Подумайте про силу связи перед тем как решить проблему зависимости жизненого цикла, а не наоборот:
При моделировании зависимость в жизненый циклах не должна усилять связи.

Если связь слабая — regular aggregation это лучший выбор:
в последствии, при развитии проекта, компоненты могут начать использовать части других компонент, что сведет диаграму на нет если у вас будет сильная жизненая зависимость.

давайте рассмотрим пример на нашей коммерческой системе:
в ней мы решили что ShopppingCart не может сущестовать без Customer (без этого наша система теряет смысл)
Мы так же решили что ShoppingCart это пуп вселенной, по крайней мере для нас, поэтому нам нужно постараться определить остальные объкты через связь с покупательской тележкой:

Результатом нашего решения будет вывод, что покупатель не может существовать без покупательской тележки, а не наоборот,
вы говорите — это магазин, ничего не покупаете — уходите :P

в чем оптимальный выбор — это остаеться на усмотрение читателя, я же покажу диаграму:



и пример кода

  1. //Uni-directional 
  2. class Customer 
  3. { 
  4.   private $_cart; 
  5.   
  6.   public function __construct() 
  7.   { 
  8.     $this->_cart = new ShoppingCart();    
  9.   } 
 10. } 
 11. 
 12. class ShoppingCart 
 13. { 
 14.   private $_items = array(); 
 15.   
 16.   public function getItems() 
 17.   { 
 18.     return $this->_items; 
 19.   } 
 20. } 
 21. //Bi-directional 
 22. class Customer 
 23. { 
 24.   private $_cart; 
 25.   
 26.   public function __construct() 
 27.   { 
 28.     $this->_cart = new ShoppingCart();    
 29.   } 
 30.   
 31.   public function getCart() 
 32.   { 
 33.     return $this->_cart; 
 34.   } 
 35.   
 36.   public function checkOutCart() 
 37.   { 
 38.     $this->getCart()->getCheckOutDetails($this); 
 39.   } 
 40.   
 41.   public function getCustomerDetails() 
 42.   { 
 43.     //. 
 44.   } 
 45. } 
 46. class ShoppingCart 
 47. {    
 48.   public function getCheckOutDetails(Customer $customer) 
 49.   { 
 50.     $customer->getCustomerDetails(); 
 51.     //. 
 52.   } 
 53. } 


* This source code was highlighted with Source Code Highlighter.


Generalizations



Generalizations — представление кода «как он есть», это связи с которыми вы уже должны были подружиться,( за время програмирования =):
интерфейсы и наследование, я просто приведу вам небольшой пример натации обоих:



асбтракный класс ProductList наследуеться от интерфейса ItemList, ShoppingCart расширяет функциональность ProductList

Dependencies:



Dependencies показывать что изменение в одной структуре может потребовать изменение в другой, во многих случаях другие типы зависимостей уже подразумивают какую-либо зависимость, но есть вы хотите описать зависимости более детально — вы можете использовать dependency, что бы описать связь между эллементами. Это подразумевает что зависимость слабая и не пригодна для использования в associative relation.

давайте посмотрим след диаграмму:



Customer зависит от WishList тк он содержит желаемые предметы покупки. Пунктирная линия показывать что getWishList это статическая операция.
Customer зависит от работы ф-ции getWishList.

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

Что бы лучше посмотреть на зависимости — давайте вглянем на наш проект с высоты птичьего полета, будем использовать пакетную диаграмму



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

спасибо за внимание
Tags:
Hubs:
Total votes 85: ↑66 and ↓19 +47
Views 61K
Comments Comments 46