В информатике композиция объектов и агрегация объектов — тесно связанные способы объединения объектов или типов данных в более сложные. В разговоре различие между композицией и агрегацией часто игнорируется. [1] Распространенными видами композиций являются объекты, используемые в объектно-ориентированном программировании , помеченные объединения , множества , последовательности и различные графовые структуры. Композиции объектов связаны со структурами данных, но не являются ими.
Композиция объектов относится к логической или концептуальной структуре информации, а не к реализации или физической структуре данных , используемой для ее представления [ требуется ссылка ] . Например, последовательность отличается от набора , поскольку (помимо прочего) порядок составленных элементов имеет значение для первого, но не для второго. Такие структуры данных, как массивы , связанные списки , хэш-таблицы и многие другие, могут использоваться для реализации любого из них. Возможно, это сбивает с толку, но некоторые из тех же терминов используются как для структур данных, так и для композитов. Например, « двоичное дерево » может относиться к любому из них: как структура данных оно является средством доступа к линейной последовательности элементов, и фактические позиции элементов в дереве не имеют значения (дерево может быть внутренне переупорядочено как угодно, без изменения его смысла). Однако, как композиция объектов, позиции имеют значение, и их изменение изменит смысл (как, например, в кладограммах ) [ требуется ссылка ] .
Объектно-ориентированное программирование основано на использовании объектов для инкапсуляции данных и поведения. Оно использует два основных метода для сборки и компоновки функциональности в более сложные: подтипизацию и композицию объектов. [2] Композиция объектов заключается в объединении объектов внутри составных объектов и в то же время в обеспечении инкапсуляции каждого объекта путем использования их четко определенного интерфейса без видимости их внутренних компонентов. В этом отношении композиция объектов отличается от структур данных, которые не обеспечивают инкапсуляцию.
Композиция объектов может также быть о группе из нескольких связанных объектов, таких как набор или последовательность объектов. Делегирование может обогатить композицию путем пересылки запросов или вызовов, сделанных включающему составному объекту, одному из его внутренних компонентов. [3]
В языках программирования на основе классов и типизированных языках типы можно разделить на составные и несоставные, а композицию можно рассматривать как отношение между типами: объект составного типа (например, car ) « имеет » объекты других типов (например, wheel ). Когда составной объект содержит несколько подобъектов одного и того же типа, им могут быть назначены определенные роли , часто различаемые именами или числами. Например, объект Point может содержать 3 числа, каждое из которых представляет расстояние по разным осям, например, «x», «y» и «z». Изучением отношений часть-целое в целом является мереология .
Композицию следует отличать от подтипирования , которое представляет собой процесс добавления деталей к общему типу данных для создания более конкретного типа данных. Например, автомобили могут быть определенным типом транспортного средства: автомобиль является транспортным средством . Подтипирование не описывает отношения между различными объектами, а вместо этого говорит о том, что объекты одного типа одновременно являются объектами другого типа. Изучение таких отношений называется онтологией .
В языках программирования на основе прототипов , таких как JavaScript , объекты могут динамически наследовать поведение от объекта-прототипа в момент их создания. Композицию следует отличать от прототипирования: вновь созданный объект наследует композицию своего прототипа, но он сам может быть создан самостоятельно.
Составные объекты могут быть представлены в хранилище путем совместного размещения составных объектов, совместного размещения ссылок или многими другими способами. Элементы внутри составного объекта могут называться атрибутами , полями , членами , свойствами или другими именами, а полученная композиция — составным типом , записью хранилища , структурой , кортежем или определяемым пользователем типом (UDT) . Подробности см. в разделе агрегации ниже.
В моделировании UML объекты могут быть концептуально составлены, независимо от реализации с помощью языка программирования. Существует четыре способа составления объектов в UML: свойство, ассоциация, агрегация и композиция: [4]
Связь между агрегатом и его компонентами является слабой связью «имеет»: компоненты могут быть частью нескольких агрегатов, к ним можно получить доступ через другие объекты, минуя агрегат, и они могут существовать дольше агрегатного объекта. [4] Состояние объекта-компонента по-прежнему является частью агрегатного объекта. [ требуется ссылка ]
Связь между композитом и его частями является сильной связью «имеет»: композитный объект несет исключительную « ответственность за существование и хранение составных объектов », составной объект может быть частью не более одного композита, и « Если удаляется составной объект, все его экземпляры частей, являющиеся объектами, удаляются вместе с ним ». Таким образом, в UML композиция имеет более узкое значение, чем обычная композиция объектов.
Графическое обозначение представляет собой:
Агрегация отличается от обычной композиции тем, что она не подразумевает владения. В композиции, когда объект-владелец уничтожается, уничтожаются и содержащиеся в нем объекты. В агрегации это не обязательно так. Например, университет владеет различными факультетами (например, химическим ), и на каждом факультете есть несколько профессоров. Если университет закроется, факультеты больше не будут существовать, но профессора на этих факультетах продолжат существовать. Таким образом, университет можно рассматривать как композицию факультетов, тогда как факультеты имеют агрегацию профессоров. Кроме того, профессор может работать более чем на одном факультете, но факультет не может быть частью более чем одного университета.
Композиция обычно реализуется таким образом, что объект содержит другой объект. Например, в C++ :
класс Профессор ; // Определено в другом месте класс Отдел { public : Отдел ( const std :: string & title ) : title_ ( title ) {} private : // Агрегация: |Профессора| могут пережить |Кафедру|. std :: vector < std :: weak_ptr < Professor >> members_ ; const std :: string title_ ; }; класс Университет { public : University () = default ; private : // Состав: |Отделы| существуют только до тех пор, пока существует факультет. std :: vector < Отдел > Faculty_ = { Отдел ( "химия" ), Отдел ( "физика" ), Отдел ( "искусства" ), }; };
При агрегации объект может содержать только ссылку или указатель на объект (и не нести за него пожизненную ответственность).
Иногда агрегацию называют композицией, когда различие между обычной композицией и агрегацией несущественно.
Приведенный выше код преобразуется в следующую диаграмму классов UML:
В компонентной объектной модели Microsoft агрегация означает, что объект экспортирует, как если бы он был их владельцем, один или несколько интерфейсов другого объекта, которым он владеет. Формально это больше похоже на композицию или инкапсуляцию , чем на агрегацию. Однако вместо реализации экспортированных интерфейсов путем вызова интерфейсов принадлежащего объекта, экспортируются сами интерфейсы принадлежащего объекта. Принадлежащий объект отвечает за обеспечение того, чтобы методы этих интерфейсов, унаследованных от IUnknown, фактически вызывали соответствующие методы владельца. Это гарантирует, что счетчик ссылок владельца правильный и все интерфейсы владельца доступны через экспортированный интерфейс, в то время как никакие другие (частные) интерфейсы принадлежащего объекта не доступны. [5]
Композиция, которая используется для хранения нескольких экземпляров составного типа данных, называется контейнментом. Примерами таких контейнеров являются массивы , ассоциативные массивы , двоичные деревья и связанные списки .
В UML включение изображается с помощью кратности 0..* или 1..*, указывая на то, что составной объект состоит из неизвестного числа экземпляров составного класса.
Объекты могут быть составлены рекурсивно, и тогда их тип называется рекурсивным типом . Примерами являются различные виды деревьев , DAG и графов . Каждый узел в дереве может быть ветвью или листом; другими словами, каждый узел является деревом в то же время, когда он принадлежит другому дереву.
В UML рекурсивная композиция изображается с помощью ассоциации, агрегации или композиции класса с самим собой.
Композитный шаблон проектирования — это объектно-ориентированный дизайн на основе составных типов, который сочетает рекурсивную композицию и включение для реализации сложных иерархий «часть-целое».
Это пример композиции на языке C.
struct Person { int age ; char name [ 20 ]; enum { job_seeking , professional , non_professional , penesioned , student } employment ; };
В этом примере примитивные (несоставные) типы int , enum {job_seeking, professional, non_professional, retired, student } и составной тип массива char[] объединяются для формирования составной структуры Person . Каждая структура Person затем «имеет» возраст, имя и тип занятости.
C называет запись структурой или структурой; объектно-ориентированные языки, такие как Java , Smalltalk и C++, часто хранят свои записи скрытыми внутри объектов ( экземпляров классов ); языки семейства ML просто называют их записями. COBOL был первым широко распространенным языком программирования , который поддерживал записи напрямую; [6] ALGOL 68 получил это от COBOL, а Pascal получил это, более или менее косвенно, от ALGOL 68. Common Lisp предоставляет структуры и классы (последние через Common Lisp Object System ). [ необходима цитата ]
01 запись клиента . 03 номер клиента фото 9(8) комп . 03 имя клиента . 05 имя-имена фото x(15) . 05 инициалы-2 фото x . 05 фамилия фото x(15) . 03 адрес клиента . 05 улица . 07 название улицы фото x(15) . 09 номер дома фото 999 комп . 05 город фото x(10) . 05 код-страны фото x(3) . 05 почтовый индекс фото x(8) . 03 сумма-долги фото 9(8) комп .
Массивы были единственным составным типом данных в Algol 60 .
dcl 1 на основе нового типа (P); 2 (a, b, c) фиксированная ячейка (31), 2 (i, j, k) плавающий, 2 р птр;выделить новый тип;
целочисленный максимум = 99;режим newtypet = [0..9] [0..макс]структура ( длинное вещественное a, b, c, короткое целое i, j, k, ссылка вещественное r);newtypet newarrayt = (1, 2, 3, 4, 5, 6, куча вещественное := 7)
Например, связанный список может быть объявлен как:
узел режима = объединение (реальный, целочисленный, сложный, строковый), список = структура (узел значение, ссылка список следующий);
В АЛГОЛЕ 68 слева от знака равенства отображается только имя типа, и, что наиболее примечательно, конструкция выполняется (и может быть прочитана) слева направо без учета приоритетов.
тип a = массив [ 1 .. 10 ] целых чисел ; b = запись a , b , c : вещественное число ; i , j , k : целое число ; конец ;
#define max 99 struct newtypet { double a , b , c ; float r ; short i , j , k ; } newarrayt [ 10 ] [ max + 1 ];
В Fortran 77 есть массивы, но отсутствуют какие-либо формальные определения записей/структур. Обычно составные структуры создавались с использованием операторов EQUIVALENCE или COMMON :
ИМЯ ПЕРСОНАЖА * 32 , АДРЕС * 32 , ТЕЛЕФОН * 16 РЕАЛЬНЫЙ ДОЛЖНЫЙ ОБЩИЙ / ПОЛЬЗОВАТЕЛЬ / ИМЯ , АДРЕС , ТЕЛЕФОН , ДОЛЖНЫЙ
тип Cust — запись Имя : Тип_имени ; Адрес : Тип_адреса ; Телефон : Тип_телефона ; Owing : Целочисленный диапазон 1. . 999999 ; конец записи ;
Ada 95 ввела концепции ООП через помеченные типы (эквивалент класса C++), Ada 2012 добавила поддержку проверки подстановки через контракты, охватывающие весь класс.
const int max = 99 ; class { public : double a , b , c ; float & r ; short i , j , k ; } newtypet [ 10 ] [ max + 1 ];
max = 99 class NewTypeT : def __init__ ( self ): self . a = self . b = self . c = 0 self . i = self . j = self . k = 0.0 # Инициализируем пример массива этого класса. newarrayt = [[ NewTypeT () for i in range ( max + 1 )] for j in range ( 10 )]
Массивы и строки были унаследованы от FORTRAN 77, и было введено новое зарезервированное слово: type
тип newtypet двойной точности a , b , c целое число * 2 i , j , k * Нет типа указателя REF REAL R конец тип тип ( newtypet ) т ( 10 , 100 )
FORTRAN 90 обновлен и включает концепцию FORTRAN IV под названием NAMELIST.
ЦЕЛОЕ ЧИСЛО :: январь = 1 , февраль = 2 , март = 3 , апрель = 4 СПИСОК ИМЕН / неделя / январь , февраль , март , апрель
Common Lisp предоставляет структуры, а стандарт ANSI Common Lisp добавляет классы CLOS.
( defclass some-class () (( f :type float ) ( i :type integer ) ( a :type ( array integer ( 10 )))))
Более подробную информацию о композиции в C/C++ см. в разделе Составной тип .
Существует тесно связанная с композицией концепция, называемая агрегацией. В разговоре различия между композицией и агрегацией часто игнорируются.
{{cite book}}
: CS1 maint: другие ( ссылка )