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

Что такое композиция java

  • автор:

Отношения между классами

Большая часть классов приложения связаны между собой. В этом разделе рассмотрим какие бывают отношения между классами в Java.

1. IS-A отношения

В ООП принцип IS-A основан на наследовании классов или реализации интерфейсов. Например, если класс HeavyBox наследует Box , мы говорим, что HeavyBox является Box ( HeavyBox IS-A Box ). Или другой пример — класс Lorry расширяет класс Car . В этом случае Lorry IS-A Car .

То же самое относится и к реализации интерфейсов. Если класс Transport реализует интерфейс Moveable , то они находятся в отношении Transport IS-A Moveable .

2. HAS-A отношения

HAS-A отношения основаны на использовании. Выделяют три варианта отношения HAS-A: ассоциация, агрегация и композиция.

Начнем с ассоциации. В этих отношениях объекты двух классов могут ссылаться друг на друга. Например, класс Horse HAS-A Halter если код в классе Horse содержит ссылку на экземпляр класса Halter :

Ассоциация

public class Halter <> 
public class Horse

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

Агрегация

Объект класса Halter создается извне Horse и передается в конструктор для установления связи. Если объект класса Horse будет удален, объект класса Halter может и дальше использоваться, если, конечно, на него останется ссылка:

public class Horse < private Halter halter; public Horse(Halter halter) < this.halter = halter; >> 

Композиция

Теперь посмотрим на реализацию композиции. Объект класса Halter создается в конструкторе, что означает более тесную связь между объектами. Объект класса Halter не может существовать без создавшего его объекта Horse:

public class Horse < private Halter halter; public Horse() < this.halter = new Halter(); >>

Правильно ли я понял тему агрегации и композиции?

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

Отслеживать
задан 14 мая 2019 в 12:58
3,027 2 2 золотых знака 14 14 серебряных знаков 35 35 бронзовых знаков

2 ответа 2

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

В целом все верно.
Композиция и агрегация являются частными случаями ассоциации.

  • Ассоциация — это когда классы имеют ссылки друг на друга, так как им необходимо взаимодействовать между собой. Например, класс Собака и класс Человек . Оба являются независимыми, самодостаточными, но иногда они взаимодействуют между собой
  • Композиция — это когда какой то класс является самодостаточным, а другие не могут независимо от него существовать. Например, класс Рука и класс Человек . Рука является частью Человека, но она не может существовать отдельно от Человека.
  • Агрегация — аналогично композиции, но здесь уже класс является самодостаточным и он может быть использован в различных классах. Например, класс Телевизор и класс Бабушка и класс Дедушка . С Телевизором Бабушка и Дедушка могут выполнять различные действия, не обязательно что только один класс.

Более подробно и с uml диаграммами можете ознакомиться по ссылке

Отслеживать
ответ дан 14 мая 2019 в 13:27
14.9k 1 1 золотой знак 22 22 серебряных знака 41 41 бронзовый знак

Разница между композицией и агрегацией в различных требованиях к дизайну класса. Вместе с тем ваше утверждение «Разница композиции и агрегации в контроле жизненного цикла.» тоже верно. Есть отличный ответ на эту тему: https://ru.stackoverflow.com/a/597085/217374

Отслеживать
ответ дан 14 мая 2019 в 13:24
idmitrij2008 idmitrij2008
128 8 8 бронзовых знаков

То есть агрегация это(про полицейского) — бери пистолет, форму, значок и иди работай? Когда мы тебя уволим, то отберем у тебя эти вещи. Мы снимем отпечатки с пистолета, возьмем твои другие «биологические» данные с формы и оценим поношенность всего этого(мы используем эти данные, если понадобится (͡° ͜ʖ ͡°) ). А потом решим, что с этим делать. Мне еще интересна тех часть вопроса. Агрегацией можно называть только использование объекта извне(не создаем в классе, принимаем его из конструктора или метода)? Или это определяется этической частью(пример полицейского, но(. ) с объектом ВНУТРИ)?

14 мая 2019 в 13:43

Не дописал(Ограничение в символах): Объект то внутри, но наш класс не имеет методов(конструктора) для получения объекта извне(ссылка).

14 мая 2019 в 13:45

Агрегация — это когда пистолет передан нашему полицескому извне (конструктор, сеттер). Композиция — это когда у полицеского есть, например, татуировка пистолета: она является частью этого полицейского и рассматривается только в составе этого конкретного полицейского. Надеюсь, я верно понял вопрос.

14 мая 2019 в 14:09

Добавил это: «Агрегация — это когда ссылка на объект класса передана извне (конструктор, сеттер). Объект дается лишь на пользование. Композиция — объект принадлежит гл. классу и неотделим.» Все правильно?

Чем отличаются наследование и композиция в Java

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

Другое важное отличие: при композиции мы можем повторно использовать код даже из final-класса, тогда как унаследоваться от него невозможно. Кроме того при композиции возможно использование кода из нескольких различных классов.

С наследованием такой трюк не сработает: в Java не поддерживается множественное наследование. Зато вы можете сделать это в C++. Кстати, всегда стоит предпочитать композицию наследованию в Java. И не только потому, что так советует Джошуа Блох в своей книге Effective Java (которая является отличным источником полезных советов для Java-программиста). Аргументы за использование композиции вы можете прочитать здесь.

Наследование и композиция

Давайте посмотрим более детально на отличия композиции и наследования. Мы рассмотрим каждый пункт достаточно подробно, но без скучных деталей.

Гибкость

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

Ограниченное повторное использование кода при наследовании

Как уже было сказано, унаследоваться в Java можно только от одного класса, а это значит, что повторно можно использовать один, и только один класс. Если вы хотите получить функциональность нескольких классов, то вам следует использовать композицию. К примеру: ваш код должен использовать аутентификацию, следовательно вам надо унаследовать класс Authenificator, для использования авторизации — Autorizer и т. д. Но, поскольку множественное наследование в Java не поддерживается, вы этого сделать не можете. Единственный выход — композиция.

Юнит-тесты

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

Final-классы

Невозможность расширить final-классы — еще одно ограничение наследования. В Java нет возможности унаследоваться от final-классов, поэтому опять единственный выход — использовать композицию для повторного использования кода.

Инкапсуляция

Последнее отличие композиции и наследования в Java заключается в их отношении к инкапсуляции. Несмотря на то, что и та, и другая техники позволяют повторно использовать код, наследование нарушает принцип инкапсуляции, поскольку подкласс зависит от поведения родительского класса. Если класс-родитель изменит свое поведение, это повлияет и на его потомков. Если классы плохо документированы и класс-потомок неправильно использует родительский, то при любом изменении родителя функциональность потомка окажется сломанной. Для того, чтобы увидеть это на примере, вы можете прочитать главы 16 и 17 Effective Java.

Чем отличаются наследование и композиция в Java 1

Вот и все, что можно сказать об отличиях композиции и наследования в Java и в объектно-ориентированном программировании вообще. Как видите, они по-разному служат одной цели: повторное использование проверенных и протестированных участков кода. Композиция при этом позволяет защитить повторно используемый класс от клиентов, тогда как наследование этого не гарантирует. Тем не менее, иногда наследование необходимо. В частности, когда вы создаете классы из одного семейства.
Перевод статьи «Difference between Inheritance and Composition in Java OOPS»

Java. Повторное использование кода в Java. Понятие композиции, наследования, делегирования. Ключевое слово extends. Примеры

Повторное использование кода в классaх. Понятие композиции, наследования, делегирования. Ключевое слово extends . Примеры

Поиск на других ресурсах:

1. Каким образом повторное использование кода применяется в классах?

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

До появления объектно-ориентированного программирования существовало процедурно-ориентированное программирование. В процедурно-ориентированном подходе для того, чтобы использовать повторно программный код, использовался метод копирования этого кода. Такой подход не был достаточно эффективен и, при увеличении кода программной системы, вызывал стремительный рост ошибок.

2. Какие существуют способы (подходы) построения классов для эффективного обеспечения повторного использования кода?

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

В объектно-ориентированных языках программирования (Java, C++, C# и прочих) существуют три способа построения классов, которые повторно используют программный код:

  • композиция (composition). В этом случае класс содержит в себе объект другого класса, программный код которого нужно использовать. Такой подход использует функциональность готового кода;
  • наследование (inheritance). Класс наследует другой код (класса) и изменяет его свойства (поведение) или добавляет собственные возможности (поведение) к унаследованному коду;
  • делегирование. Это что-то промежуточное между композицией и наследованием.

Эти способы еще называют отношениями между классами. Во всех способах строятся новые классы (типы) на базе уже существующих классов (типов).

3. Примеры композиции в классах

Пример 1. Класс B включает в себя объекты (экземпляры) класса A . Значение объектов класса A инициализируются разными способами:

  • непосредственно (объект a1 );
  • в конструкторе (объект a2 ).
// Демонстрация композиции в классе class A < int a; // внутренняя переменная класса A // конструктор A() < a = 1; > // методы класса A void SetA(int a) < this.a = a; > int GetA() < return a; > > public class B < int b; // внутренняя переменная класса B // композиция: в классе B объявляются объекты класса A A a1 = new A(); A a2; // конструктор класса B B() < b = 0; a2 = new A(); a2.SetA(15); > // методы доступа к внутренней переменной b void SetB(int nb) < b = nb; > int GetB() < return b; > public static void main(String[] args) < // композиция: в классе B объявляются объекты класса A B objB = new B(); // объект (екземпляр) класса B // демонстрация доступа int t; // доступ к объекту a2 класса A, в котором реализован метод GetA() t = objB.a2.GetA(); // t = 15 // доступ к объекту a1 класса A t = objB.a1.GetA(); // t = 1 System.out.println(t); > >

Пример 2. Класс Pixel содержит объект класса Point .

// Класс Point, описывающий точку на плоскости class Point < int x, y; // внутренние переменные // методы доступа void SetXY(int nx, int ny) < x = nx; y = ny; > int GetX() < return x; > int GetY() < return y; > > // Класс Pixel, содержащий в себе объект класса Point // Демонстрация композиции public class Pixel < int color; Point p; // объект класса Point - композиция // конструктор Pixel() < color = 0; p = new Point(); // виделить память для объекта p - обязательно > int GetColor() < return color; > void SetXYColor(int nx, int ny, int ncolor) < // в классе Pixel формируются значения объекта класса Point p.SetXY(nx, ny); // вызов метода объекта p класса Point color = ncolor; > public static void main(String[] args) < // демонстрация использования композиции Pixel px = new Pixel(); px.SetXYColor(4, 7, 5); // проверка // доступ к методам класса Point через объект p, который объявлен в классе Pixel int d = px.p.GetX(); // d = 4 d = px.p.GetY(); // d = 7 px.p.SetXY(12, 23); d = px.p.GetX(); // вызов метода класса Pixel d = px.GetColor(); // d = 5 System.out.println("d color: #333300;">⇑

4. Какая общая форма простейшего наследования классом другого класса. Ключевое слово extends

Если в классе B нужно унаследовать программный код класса A, то простейшая общая форма такого объявления следующая:

class A < // тело класса A > class B extends A < // тело класса B >

В этом случае методы и внутренние переменные класса A есть доступны в классе B . Здесь есть одно ограничение: доступными в классе B есть только методы и переменные, которые не содержат в объявлении модификатор доступа private .

5. Примеры наследования в классах

Пример 1. Пример наследования суперкласса A подклассом B . В подклассе B наследуются:

  • внутренняя переменная a класса A ;
  • внутренний метод SetA() класса A .

В методе Demo() подкласса B демонстрируется доступ к переменной и методу суперкласса A .

// суперкласс (базовый класс) class A < int a; // внутренняя переменная класса A // внутренний метод класса A void SetA(int na) < a = na; > > // подкласс B (наследует поля и методы суперкласса A) public class B extends A < int b; // внутренняя переменная класса B // внутренний метод класса B void SetB(int nb) < b = nb; > // демонстрационный метод класса B void Demo() < // доступ к полям и методам класса A a = 23; SetA(93); // доступ к полям и методам класса B b = 90; SetB(50); > >

Пример 2. Пусть дан суперкласс Point , который описывает точку на плоскости. Суперкласс Point есть базовым для подкласса Pixel . Иными словами подкласс Pixel расширяет возможности суперкласса Point путем добавления дополнительной переменной color и методов SetColor() , SetXYColor() .

class Point < int x, y; void SetXY(int nx, int ny) < x = nx; y = ny; > > // класс Pixel наследует класс Point public class Pixel extends Point < int color; void SetColor(int ncolor) < color = ncolor; > void SetXYColor(int nx, int ny, int ncolor) < // в классе Pixel доступны внутренние переменные и методы класса Point x = nx; y = ny; color = ncolor; > public static void main(String[] args) < // демонстрация использования наследования Pixel p1 = new Pixel(); p1.SetXY(4, 6); // доступ к методу класса Point из объекта класса Pixel // проверка int d = p1.x; // доступ к внутренней переменной класса Point через объект класса Pixel > >

В функции main() класса Pixel создается объект (экземпляр) класса Pixel . В экземпляре происходит доступ к переменной x , которая объявляется в классе Point . Такой код есть корректным, так как класс (подкласс) Pixel наследует класс (суперкласс) Point . Это есть особенностью (преимуществом) наследования, при котором можно расширять возможности уже существующего класса. Класс Pixel есть надмножеством над классом Point .

6. Пример объединения композиции и наследования

На примере объявления трех классов демонстрируется объединение композиции и наследования.

Объявляется три класса с именами Point , Line , LineColor . Между классами Point и Line реализована композиция. Класс Line содержит объявление объектов класса Point .
Между классами LineColor и Line реализована наследственность. Класс LineColor наследует внутренние переменные и методы класса Line .
Схема объединения изображена на рисунке.

Java. Схема объединения композиции и наследования для трех классов

Рисунок. Схема объединения композиции и наследования для трех классов

Исходный код модуля с разработанными классами.

// объединение композиции и наследования // класс, который описывает точку на плоскости class Point < int x, y; void SetXY(int nx, int ny) < x = nx; y = ny; > int GetX() < return x; > int GetY() < return y; > > // линия, состоящая из двух точек class Line < // композиция Point p1; Point p2; // конструктор класса Line Line() < p1 = new Point(); p2 = new Point(); p1.SetXY(0, 0); p2.SetXY(1, 1); > // методы доступа Point GetP1() < return p1; > Point GetP2() < return p2; > void SetPoints(Point np1, Point np2) < p1.SetXY(np1.GetX(), np1.GetY()); p2.SetXY(np2.GetX(), np2.GetY()); > > // класс, расширяющий клас Line (добавляет цвет) public class LineColor extends Line < int color; // добавлена внутренняя переменная color - цвет линии LineColor() // конструктор класса LineColor() < color = 1; > // метод Length() класса LineColor использует методы класса Line // длина линиии double Length() < double len; int x1, y1, x2, y2; // метод Length имеет доступ к p1 и p2 класса Line x1 = p1.GetX(); y1 = p1.GetY(); x2 = p2.GetX(); y2 = p2.GetY(); len = Math.sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)); return len; > public static void main(String[] args) < // демонстрация сочетания композиции и наследственности LineColor lc = new LineColor(); // экземпляр класса LineColor Point pt1, pt2; // дополнительные переменные double length; pt1 = new Point(); pt2 = new Point(); pt1.SetXY(3, 4); pt2.SetXY(5, 7); lc.SetPoints(pt1, pt2); length = lc.Length(); // length = 3.605551275463989 System.out.println("Length https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"> 



7. Особенности делегирования по сравнению с наследованием и композицией. Пример

Делегирование есть промежуточным звеном между наследственностью и композицией. Следующий пример объясняет суть делегирования.

class A < // метод класса A void MethodA() < . > // . > // класс B реализует делегирование class B < private A objA = new A(); // делегированный метод Method() < obj.MethodA(); // переадресация к встроенному объекту obj > >

При делегировании класс A есть включенным в класс B как в случае с композицией. То есть класс B содержит объект класса A . Но доступ к методам класса A происходит так, если бы класс B был унаследован от класса A. Это осуществляется путем переопределения метода Method() класса A в классе B :

MethodA()

После такого переопределения обращение к методу MethodA() класса B будет выглядеть так если бы MethodA() был унаследован:

. // объявить объект класса B B obj = new B(); // обращение к MethodA() класса B, а выглядит как к методу MethodA() класса A B.MethodA(); // будет вызван B.objA.MethodA() .

Такая организация отношения между классами называется делегированием. Метод MethodA() класса B называется делегированным методом.

8. Какие отличия между композицией и наследованием?

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

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

Наследование позволяет расширять возможности нового класса с точки зрения его специализации. Это значит, что создается специализированная версия уже существующего класса. То есть, берется уже существующий класс (базовый класс) и создается его новая специализированная версия. Как правило, в роли базового класса выступает некий класс общего назначения, в котором выделены общие черты задачи. Наследованием выражает взаимосвязь is-a («есть» или «является»).

Композиция используется, когда нужно использовать функциональность уже существующего класса в другом (новосозданном) классе. В этом случае в новосозданном классе объявляется объект класса, функциональность которого нужно использовать. Композиция является одним из видов взаимосвязи has-a (клас «содержит»).

Объект класса в другом классе может быть скрытым ( private ), открытым ( public ) или защищенным ( protected ).

Связанные темы

  • Наследование. Основные понятия. Базовый класс и производный класс. Ключевое слово extends . Скрытие данных в унаследованных классах. Модификаторы доступа private , protected , public
  • Инициализация переменных в методах класса. Инициализация членов данных класса. Способы инициализации членов данных класса

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

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