Что такое композиция в программировании
Перейти к содержимому

Что такое композиция в программировании

  • автор:

Композиция (программирование)

Агрегирование в общем смысле — это объединение нескольких элементов в единое целое. Результат агрегирования называют агрегатом.

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

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

На базе агрегирования реализуется методика делегирования, когда поставленная перед внешним объектом задача перепоручается внутреннему объекту, специализирующемуся на решении задач такого рода.

Wikimedia Foundation . 2010 .

  • Композиция «Золотое руно»
  • Композиция (музыка)

Смотреть что такое «Композиция (программирование)» в других словарях:

  • Агрегирование (программирование) — В этой статье не хватает ссылок на источники информации. Информация должна быть проверяема, иначе она может быть поставлена под сомнение и удалена. Вы можете отредактировать эту статью, добавив ссылки на авторитетные источники … Википедия
  • Субъектно-ориентированное программирование — Парадигмы программирования Агентно ориентированная Компонентно ориентированная Конкатенативная Декларативная (контрастирует с Императивной) Ограничениями Функциональная Потоком данных Таблично ориентированная (электронные таблицы) Реактивная … Википедия
  • Класс (программирование) — У этого термина существуют и другие значения, см. Класс. Класс в программировании набор методов и функций. Другие абстрактные типы данных метаклассы, интерфейсы, структуры, перечисления характеризуются какими то своими, другими… … Википедия
  • Класс (объектно-ориентированное программирование) — Класс, наряду с понятием «объект», является важным понятием объектно ориентированного подхода в программировании (хотя существуют и бесклассовые объектно ориентированные языки, например, Прототипное программирование). Под классом подразумевается… … Википедия
  • Функциональная зависимость (программирование) — Функциональная зависимость концепция, лежащая в основе многих вопросов, связанных с реляционными базами данных, включая, в частности, их проектирование. Математически представляет бинарное отношение между множествами атрибутов данного… … Википедия
  • That’s the Way Love Goes — «That’s the Way Love Goes» Сингл Джанет Джексон из альбома janet … Википедия
  • New Order — Об альбоме группы Testament см. статью The New Order. New Order New … Википедия
  • Диаграмма классов — Для улучшения этой статьи желательно?: Викифицировать статью. В UML диаграмма классов является типом диаграммы статичес … Википедия
  • Vision of Love — «Vision of Love» Сингл Мэрайи Кэри из альбома Mariah Carey Выпущен 15 мая 1990 Формат CD сингл Кассетный сингл 7 сингл … Википедия
  • Music (альбом Мадонны) — У этого термина существуют и другие значения, см. Music. Music … Википедия

Агрегация и композиция

Здравствуйте! Всегда считал, что агрегация — это синоним композиции, однако наткнулся на блог в интернете, где приводятся отличия композиции от агрегации. Мне это снесло крышу. Поясните, пожалуйста, плюсы/минусы и того и другого на небольших примерах. Как это влияет на расширяемость, тестируемость и т. д.

Отслеживать
11.5k 8 8 золотых знаков 42 42 серебряных знака 70 70 бронзовых знаков
задан 28 ноя 2016 в 6:36
2,622 1 1 золотой знак 17 17 серебряных знаков 30 30 бронзовых знаков
Там пояснено достаточно подробно. Вы лучше конкретные вопросы напишите.
28 ноя 2016 в 10:56

да особо нечего спросить так сходу. хорошо бы если бы кто-нибудь разъяснил плюсы/минусы и того и другого на небольших примерах. как это влияет на расширяемость, тестируемость и т.д.

28 ноя 2016 в 11:45

1 ответ 1

Сортировка: Сброс на вариант по умолчанию

Существует несколько видов взаимодействия объектов, объединенных под общим понятием «Has-A Relationship» или «Part Of Relationship». Это отношение означает, что один объект является составной частью другого объекта.

Существует два подвида этого отношения: если один объект создает другой объект и время жизни «части» зависит от времени жизни целого, то это называется «композиция», если же один объект получает ссылку (указатель) на другой объект в процессе конструирования, то это уже агрегация.

Давайте рассмотрим пример из .NET Framework, чтобы увидеть, какие ограничения/последствия несут эти отношения: StringWriter + StringBuilder .

Класс StringWriter — это специализированная версия класса TextWriter , которые активно используются при сериализации и для получения текстового представления объектов.

Конкретно StringWriter создает строковое представление объекта или графа объектов и опирается на экземпляр StringBuilder в своей работе. Т.е. мы можем сказать, что ‘StringWriter HAS A StringBuilder’ или ‘StringBuilder is part of StringWriter’. Теперь давайте посмотрим, как решить, должен ли StringWriter получать экземпляр StringBuilder -а извне или создавать его?

С одной стороны, нам, как клиенту класса StringWriter часто бывает все равно, что именно используется внутри этого класса для получения строкового представления. Это значит, что с точки зрения простоты использования лучше, чтобы StringWriter создавал экземпляр StringBuilder -а самостоятельно.

Но, с другой стороны, конкретный объект StringWriter -а может отвечать лишь за получения части строкового представления, а другая часть строки может вычисляться другим способом. С этой точки зрения, лучше, чтобы StringWriter принимал экземлпяр StringBuilder -а в конструкторе. Это же справедливо и для высоконагруженных систем, в которых разумно использование пула объектов.

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

Другими словами, выбор между композицией и агрегацией основан на соблюдении балланса между различными требованиями в дизайне:

Композиция: объект A управляет временем жизни объекта B

  • Композиция позволяет скрыть отношение использования объектов от глаз клиента.
  • Делает API использования класса более простым и позволяет перейти от использования одного класса, к другому (например, StringWriter мог бы поменять реализацию и начать использовать другой тип, например CustomStringBuilder ).
  • Отношение достаточно жесткое, поскольку один объект должен уметь создавать другой: он должен знать конкретный тип и иметь доступ к функции создания. Композиция не позволяет использовать интерфейсы (без привлечения фабрик) и требует, чтобы класс имел доступ к конструктору другого класса: представьте, что конструктор StringBuilder -а является внутренним или же это интерфейс IStringBuilder и только клиенский код знает, какой экземпляр должен использоваться здесь и сейчас.

Агрегация: объект А получает ссылку на объект B

  • Более слабая связанность между объектом и его клиентом. Теперь мы можем использовать интерфейсы и одному объекту не нужно знать, как именно создавать другой объект.
  • Большая гибкость. Вытекает из первого пункта
  • Выставление наружу деталей реализации. Поскольку клиент класса должен предоставить зависимость в момент создания объекта (передать экземпляр StringBuilder -а в момент создания StringWriter -а, то сам факт этого отношения становится известен клиенту.
  • Из первого пункта вытекает увеличение сложности в работе клиентов, а также большая «жесткость» решения в долгосрочной перспективе. Теперь автор класса TextWriter уже не может принять решение самостоятельно и перейти от StringBuilder -а к чему-то другому. Да, можно «добавить еще один уровень абстракции» и выделить интерфейс IStringBuilder , но разорвать это отношение совсем будет невозможно без поломки всех существующих клиентов.

В заключении: дизайн — это поиск компромисса между различными факторами. Композиция проще с точки зрения клиентов класса, но налагает определенные ограничения: «целое» должно уметь создавать «составную часть». Агрегация гибче, но налагает другие ограничения: теперь «целое» не скрывает о существовании «составной части», а значит и не сможет заменить ее на другую «составную часть» в будущем.

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

Композиция в Python

Еще одной особенностью объектно-ориентированного программирования является возможность реализовывать так называемый композиционный подход. Заключается он в том, что есть класс-контейнер, он же агрегатор, который включает в себя вызовы других классов. В результате получается, что при создании объекта класса-контейнера, также создаются объекты других классов.

Чтобы понять, зачем нужна композиция в программировании, проведем аналогию с реальным миром. Большинство биологических и технических объектов состоят из более простых частей, также являющихся объектами. Например, животное состоит из различный органов (сердце, желудок), компьютер — из различного «железа» (процессор, память).

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

Рассмотрим на примере реализацию композиции в Python. Пусть, требуется написать программу, которая вычисляет площадь обоев для оклеивания помещения. При этом окна, двери, пол и потолок оклеивать не надо.

Прежде, чем писать программу, займемся объектно-ориентированным проектированием. То есть разберемся, что к чему. Комната – это прямоугольный параллелепипед, состоящий из шести прямоугольников. Его площадь представляет собой сумму площадей составляющих его прямоугольников. Площадь прямоугольника равна произведению его длины на ширину.

Куб

По условию задачи обои клеятся только на стены, следовательно площади верхнего и нижнего прямоугольников нам не нужны. Из рисунка видно, что площадь одной стены равна xz , второй – уz . Противоположные прямоугольники равны, значит общая площадь четырех прямоугольников равна S = 2xz + 2уz = 2z(x+y) . Потом из этой площади надо будет вычесть общую площадь дверей и окон, поскольку они не оклеиваются.

Можно выделить три типа объектов – окна, двери и комнаты. Получается три класса. Окна и двери являются частями комнаты, поэтому пусть они входят в состав объекта-помещения.

Для данной задачи существенное значение имеют только два свойства – длина и ширина. Поэтому классы «окна» и «двери» можно объединить в один. Если бы были важны другие свойства (например, толщина стекла, материал двери), то следовало бы для окон создать один класс, а для дверей – другой. Пока обойдемся одним, и все что нам нужно от него – площадь объекта:

class WinDoor: def __init__(self, x, y): self.square = x * y

Класс «комната» – это класс-контейнер для окон и дверей. Он должен содержать вызовы класса «ОкноДверь».

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

class Room: def __init__(self, x, y, z): self.square = 2 * z * (x + y) self.wd = [] def add_wd(self, w, h): self.wd.append(WinDoor(w, h)) def work_surface(self): new_square = self.square for i in self.wd: new_square -= i.square return new_square r1 = Room(6, 3, 2.7) print(r1.square) # выведет 48.6 r1.add_wd(1, 1) r1.add_wd(1, 1) r1.add_wd(1, 2) print(r1.work_surface()) # выведет 44.6

Практическая работа

Приведенная выше программа имеет ряд недочетов и недоработок. Требуется исправить и доработать, согласно следующему плану.

При вычислении оклеиваемой поверхности мы не «портим» поле self.square . В нем так и остается полная площадь стен. Ведь она может понадобиться, если в списке wd произойдут изменения, и придется заново вычислять оклеиваемую площадь.

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

Исправьте код так, чтобы у объектов Room было четыре поля – width , length , height и wd . Площади (полная и оклеиваемая) должны вычислять лишь при необходимости путем вызова методов.

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

Разработайте интерфейс программы. Пусть она запрашивает у пользователя данные и выдает ему площадь оклеиваемой поверхности и количество необходимых рулонов.

Курс с примерами решений практических работ:
pdf-версия

X Скрыть Наверх

Объектно-ориентированное программирование на Python

Что такое композиция в программировании

Скачай курс
в приложении

Перейти в приложение
Открыть мобильную версию сайта

© 2013 — 2024. Stepik

Наши условия использования и конфиденциальности

Get it on Google Play

Public user contributions licensed under cc-wiki license with attribution required

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *