В информатике композиция объектов и агрегирование объектов — это тесно связанные способы объединения объектов или типов данных в более сложные. В разговоре часто игнорируется различие между композицией и агрегацией. [1] Распространенными видами композиций являются объекты, используемые в объектно-ориентированном программировании , тегированные объединения , множества , последовательности и различные графовые структуры. Композиции объектов относятся к структурам данных, но не являются ими.
Композиция объекта относится к логической или концептуальной структуре информации, а не к реализации или физической структуре данных, используемой для ее представления . Например, последовательность отличается от набора тем, что (помимо прочего) порядок составленных элементов имеет значение для первого, но не для второго. Структуры данных, такие как массивы , связанные списки , хеш-таблицы и многие другие, могут использоваться для реализации любого из них. Возможно, это сбивает с толку то, что некоторые из одних и тех же терминов используются как для структур данных, так и для композитов. Например, « двоичное дерево » может относиться к любому из следующих вариантов: как структура данных, оно является средством доступа к линейной последовательности элементов, а фактическое положение элементов в дереве не имеет значения (дерево можно внутренне переупорядочить как угодно). не меняя его смысла). Однако в качестве объектной композиции позиции релевантны, и их изменение приведет к изменению значения (как, например , в кладограммах ) .
Объектно-ориентированное программирование основано на объектах для инкапсуляции данных и поведения. Он использует два основных метода сборки и объединения функциональности в более сложные: подтипирование и композицию объектов. [2] Композиция объектов — это объединение объектов внутри составных объектов и в то же время обеспечение инкапсуляции каждого объекта с использованием их четко определенного интерфейса без видимости их внутренних компонентов. В этом отношении композиция объектов отличается от структур данных, которые не требуют инкапсуляции.
Композиция объектов также может представлять собой группу из нескольких связанных объектов, например набор или последовательность объектов. Делегирование может обогатить композицию путем перенаправления запросов или вызовов, сделанных к включающему составному объекту, одному из его внутренних компонентов. [3]
В классовых и типизированных языках программирования типы можно разделить на составные и несоставные типы, а композицию можно рассматривать как связь между типами: объект составного типа (например, автомобиль ) « имеет » объекты других типов ( например, колесо ). Когда составной объект содержит несколько подобъектов одного типа, им могут быть назначены определенные роли , часто отличающиеся именами или номерами. Например, объект Point может содержать три числа, каждое из которых представляет расстояние по разным осям, например «x», «y» и «z». Изучение отношений части и целого в целом является мереологией .
Композицию следует отличать от подтипирования , которое представляет собой процесс добавления деталей к общему типу данных для создания более конкретного типа данных. Например, автомобили могут относиться к определенному типу транспортных средств: car — это транспортное средство . Подтипирование не описывает отношения между различными объектами, а говорит о том, что объекты одного типа одновременно являются объектами другого типа. Изучением таких отношений является онтология .
В языках программирования, основанных на прототипах , таких как JavaScript , объекты могут динамически наследовать поведение объекта-прототипа в момент их создания. Композицию следует отличать от прототипирования: вновь созданный объект наследует композицию своего прототипа, но сам может быть составлен самостоятельно.
Составные объекты могут быть представлены в хранилище путем совместного размещения составных объектов, совместного размещения ссылок или многими другими способами. Элементы внутри составного объекта могут называться атрибутами , полями , членами , свойствами или другими именами, а результирующая композиция — составным типом , записью хранения , структурой , кортежем или определяемым пользователем типом (UDT) . Подробную информацию см. в разделе агрегирования ниже.
При моделировании UML объекты могут быть концептуально составлены независимо от реализации на языке программирования. В UML существует четыре способа составления объектов: свойство, ассоциация, агрегация и композиция: [4]
Связь между агрегатом и его компонентами представляет собой слабую связь «имеет»: компоненты могут быть частью нескольких агрегатов, к ним можно получить доступ через другие объекты, не проходя через агрегат, и они могут пережить агрегатный объект. [4] Состояние составного объекта по-прежнему является частью составного объекта. [ нужна цитата ]
Связь между составным объектом и его частями представляет собой сильную связь «имеет»: составной объект несет исключительную « ответственность за существование и хранение составных объектов », составной объект может быть частью не более чем одного составного объекта, и « При удалении составного объекта все экземпляры его частей, являющиеся объектами, удаляются вместе с ним ». Таким образом, в UML композиция имеет более узкое значение, чем обычная композиция объектов.
Графическое обозначение представляет:
Агрегация отличается от обычной композиции тем, что не предполагает владения. В композиции, когда объект-владелец уничтожается, уничтожаются и содержащиеся в нем объекты. В совокупности это не обязательно так. Например, в университете есть различные кафедры (например, химия ), и на каждой кафедре работает несколько профессоров. Если университет закроется, кафедр больше не будет, но профессора на этих кафедрах продолжат существовать. Таким образом, университет можно рассматривать как совокупность кафедр, тогда как кафедры представляют собой совокупность профессоров. Кроме того, профессор мог работать более чем на одной кафедре, но кафедра не могла входить более чем в один университет.
Композиция обычно реализуется таким образом, что один объект содержит другой объект. Например, в С++ :
классный профессор ; // Определено в другом месте класс Department { public : Department ( const std :: string & title ) : title_ ( title ) {} частный : // Агрегация: |Профессора| может пережить |Департамент|. std :: vector < std :: weak_ptr < Профессор >> members_ ; const std :: строка title_ ; }; класс University { public : University () = по умолчанию ; Private : // Состав: |Кафедры|существуют только до тех пор, пока существует факультет. std :: vector < Кафедра > факультет_ = { Кафедра ( «Химия» ), Кафедра ( «Физика» ), Кафедра ( «Искусство» ), }; };
При агрегировании объект может содержать только ссылку или указатель на объект (и не нести за него пожизненную ответственность).
Иногда агрегацию называют композицией, когда различие между обычной композицией и агрегацией неважно.
Приведенный выше код преобразуется в следующую диаграмму классов UML:
В объектной модели компонентов Microsoft агрегирование означает, что объект экспортирует, как если бы он был его владельцем, один или несколько интерфейсов другого объекта, которым он владеет. Формально это больше похоже на композицию или инкапсуляцию , чем на агрегацию. Однако вместо реализации экспортированных интерфейсов путем вызова интерфейсов принадлежащего объекта экспортируются сами интерфейсы принадлежащего объекта. Принадлежащий объект отвечает за обеспечение того, чтобы методы этих интерфейсов, унаследованных от IUnknown , действительно вызывали соответствующие методы владельца. Это необходимо для того, чтобы гарантировать, что счетчик ссылок владельца правильный и все интерфейсы владельца доступны через экспортированный интерфейс, в то время как другие (частные) интерфейсы принадлежащего объекта недоступны. [5]
Композиция, которая используется для хранения нескольких экземпляров составного типа данных, называется вложением. Примерами таких контейнеров являются массивы , ассоциативные массивы , двоичные деревья и связанные списки .
В UML включение изображается с кратностью 0..* или 1..*, что указывает на то, что составной объект состоит из неизвестного количества экземпляров составного класса.
Объекты можно составлять рекурсивно, и их тип тогда называется рекурсивным типом . Примеры включают в себя различные виды деревьев , группы DAG и графы . Каждый узел дерева может быть ветвью или листом; другими словами, каждый узел является деревом в то же время, когда он принадлежит другому дереву.
В UML рекурсивная композиция изображается с помощью ассоциации, агрегации или композиции класса с самим собой.
Шаблон составного проектирования — это объектно-ориентированный дизайн, основанный на составных типах, который сочетает в себе рекурсивную композицию и включение для реализации сложных иерархий части-целого.
Это пример композиции в C.
struct Person { int age ; имя персонажа [ 20 ]; enum { ищу работу , профессиональный , непрофессиональный , пенсионер , студент } занятость ; };
В этом примере примитивные (несоставные) типы int , enum {job_seeking, professional, non_professional, пенсионный, студент } и составной тип массива char[] объединяются, образуя составную структуру Person . Каждая структура Person «имеет» возраст, имя и тип занятости.
C называет запись структурой или структурой; объектно-ориентированные языки, такие как Java , Smalltalk и C++, часто скрывают свои записи внутри объектов ( экземпляров классов ); языки семейства ML называют их просто записями. COBOL был первым широко распространенным языком программирования , который напрямую поддерживал записи; [6] АЛГОЛ 68 получил его от COBOL, а Паскаль получил его, более или менее косвенно, от АЛГОЛ 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 (а, б, в) фиксированный бункер(31), 2 (i, j, k) плавающий, 2 р птр;выделить новый тип;
интервал Макс = 99;режим newtypet = [0..9] [0..max]struct ( длинный реальный a, b, c, короткий int i, j, k, ref реальный r);newtypet newarrayt = (1, 2, 3, 4, 5, 6, куча вещественная: = 7)
Например, связанный список может быть объявлен как:
режим node = объединение (real, int, compl, строка), list = struct (значение узла, список ссылок следующий);
В АЛГОЛе 68 слева от равенства появляется только имя типа, и, что особенно важно, конструкция создается – и может быть прочитана – слева направо, без учета приоритетов.
введите a = массив [ 1 .. 10 ] целых чисел ; б = запись а , б , с : реальный ; я , j , k : целое число ; конец ;
#define max 99 struct newtypet { double a , b , c ; плавать р ; короткий я , j , k ; } Новый массив [ 10 ] [ макс + 1 ];
В Фортране 77 есть массивы, но отсутствуют какие-либо формальные определения записей/структур. Обычно составные структуры создавались с использованием операторов EQUIVALENCE или COMMON :
ИМЯ ПЕРСОНАЖА * 32 , АДРЕС * 32 , ТЕЛЕФОН * 16 REAL OWING COMMON / CUST / NAME , ADDR , PHONE , OWING
тип Cust — имя записи : Name_Type ; Адрес : Тип_адреса ; Телефон : Тип_телефона ; Должен : Целочисленный диапазон 1. . 999999 ; завершить запись ;
В Ada 95 концепции ООП реализованы через тегированные типы (эквивалент класса C++), в Ada 2012 добавлена поддержка проверки замены посредством общеклассовых контрактов.
const int max = 99 ; класс { общественный : двойной а , б , с ; плавать & р ; короткий я , j , k ; } Newtypet [ 10 ] [ макс + 1 ];
max = 99 класс NewTypeT : def __init__ ( self ): self . а = сам . б = сам . с = 0 сам . я = я . j = сам . k = 0.0 # Инициализировать пример массива этого класса. newarrayt = [[ NewTypeT () для i в диапазоне ( max + 1 )] для j в диапазоне ( 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 целое число ) ( a :type ( целое число массива ( 10 )))))
Дополнительные сведения о композиции в C/C++ см. в разделе Составной тип .
Существует тесно связанное с композицией понятие, называемое агрегацией. В разговоре часто игнорируются различия между композицией и агрегацией.
{{cite book}}
: CS1 maint: другие ( ссылка )