Взаимодействия объектов в java

Композиция, агрегация и ассоциация в Java

Изучите свойства и представление композиции, агрегации и ассоциации в Java.

1. введение

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

В этом уроке мы сосредоточимся на подходе Java к трем иногда легко смешиваемым типам отношений: композиция, агрегация и ассоциация.

2. Состав

Композиция -это тип отношений “принадлежит”. Это означает, что один из объектов является логически более крупной структурой, которая содержит другой объект. Другими словами, это часть или член другого объекта.

В качестве альтернативы, мы часто называем это отношением “имеет-а” (в отличие от отношения “есть-а”, которое является наследованием ).

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

Композиция-это сильный вид отношений “имеет-а”, потому что содержащий объект владеет им. Таким образом, жизненные циклы объектов связаны. Это означает, что если мы уничтожим объект-владельца, его члены также будут уничтожены вместе с ним. Например, комната разрушается вместе со зданием в нашем предыдущем примере.

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

Читайте также:  Program calculator in python

С точки зрения мощности, содержащий объект может иметь столько частей, сколько мы захотим. Однако все детали должны иметь ровно один контейнер .

2.1. UML

В UML мы обозначаем композицию следующим символом:

Обратите внимание, что алмаз находится в содержащем его объекте и является основанием линии, а не наконечником стрелы. Для ясности мы тоже часто рисуем наконечник стрелы:

Итак, мы можем использовать эту конструкцию UML для нашего примера здания:

2.2. Исходный код

В Java мы можем смоделировать это с помощью нестатического внутреннего класса:

В качестве альтернативы мы также можем объявить этот класс в теле метода. Не имеет значения, является ли это именованный класс, анонимный класс или лямбда:

class Building < Room createAnonymousRoom() < return new Room() < @Override void doInRoom() <>>; > Room createInlineRoom() < class InlineRoom implements Room < @Override void doInRoom() <>> return new InlineRoom(); > Room createLambdaRoom() < return () -><>; > interface Room < void doInRoom(); >>

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

Обычно содержащий объект хочет получить доступ к своим членам. Поэтому мы должны хранить их ссылки:

class Building < Listrooms; class Room <> >

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

3. Агрегация

Агрегация также является отношением “есть-есть”. Что отличает его от композиции, так это то, что он не предполагает владения. В результате жизненный цикл объектов не привязан: каждый из них может существовать независимо друг от друга.

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

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

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

3.1. UML

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

Поэтому представления UML также очень похожи. Разница лишь в том, что алмаз пуст:

Тогда для автомобилей и колес мы бы сделали:

3.2. Исходный код

В Java мы можем моделировать агрегацию с помощью простой старой ссылки:

class Wheel <> class Car < Listwheels; >

Членом может быть любой тип класса, кроме нестатического внутреннего класса.

В приведенном выше фрагменте кода оба класса имеют свой отдельный исходный файл. Однако мы также можем использовать статический внутренний класс:

class Car < Listwheels; static class Wheel <> >

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

class Wheel < Car car; >class Car < Listwheels; >

4. Ассоциация

Ассоциация-это самая слабая связь между этими тремя. Это не отношение “имеет-а” , ни один из объектов не является частью или членом другого.

Ассоциация означает только то, что объекты “знают” друг друга. Например, мать и ее ребенок.

4.1. UML

В UML мы можем отметить ассоциацию стрелкой:

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

Мы можем представить мать и ее ребенка в UML, тогда:

4.2. Исходный код

В Java мы можем моделировать ассоциацию так же, как и агрегацию:

class Child <> class Mother < Listchildren; >

Но подождите, как мы можем определить, означает ли ссылка агрегацию или ассоциацию?

Ну, мы не можем. Разница только логична: является ли один из объектов частью другого или нет.

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

class Child < Mother mother; >class Mother < Listchildren; >

5. UML Sidenote

Для ясности иногда мы хотим определить мощность отношения на диаграмме UML. Мы можем сделать это, записав его на концах стрелки:

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

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

6. Сложный Пример

Давайте рассмотрим (немного) более сложный пример!

Мы смоделируем университет, в котором есть свои кафедры. На каждой кафедре работают профессора, у которых также есть друзья друг среди друга.

Будут ли кафедры существовать после того, как мы закроем университет? Конечно, нет, поэтому это композиция.

Но профессора все равно будут существовать (надеюсь). Мы должны решить, что более логично: считать ли профессоров частью кафедр или нет. Альтернативно: являются ли они членами департаментов или нет? Да, это так. Следовательно, это агрегация. Кроме того, профессор может работать на нескольких кафедрах.

Отношения между профессорами являются ассоциативными, потому что нет никакого смысла говорить, что профессор является частью другого.

В результате мы можем смоделировать этот пример со следующей диаграммой UML:

И код Java выглядит следующим образом:

class University < Listdepartment; > class Department < Listprofessors; > class Professor < Listdepartment; List friends; >

Обратите внимание, что если мы полагаемся на термины “имеет-а”, “принадлежит”, “член”, “часть” и так далее , мы можем легче идентифицировать отношения между нашими объектами.

7. Заключение

В этой статье мы рассмотрели свойства и представление композиции, агрегации и ассоциации. Мы также видели, как моделировать эти отношения в UML и Java.

Как обычно, примеры доступны на GitHub .

Читайте ещё по теме:

Источник

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

Большая часть классов приложения связаны между собой. В этом разделе рассмотрим какие бывают отношения между классами в 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 :

Ассоциация

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

Агрегация

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

Композиция

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

Источник

Взаимодействие объектов

— Привет, Амиго. Сегодня я хочу рассказать тебе, как устроена типичная программа на Java. Главная новость: Каждая программа на Java состоит из классов и объектов.

— Что такое классы, я уже знаю. А что такое объекты?

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

— В программировании на Java все точно так же.

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

— Сначала мы пишем классы (делаем чертежи), а потом, во время исполнения программы, на основе этих классов Java-машина создает объекты. Точно так же, как корабли создаются на основе чертежей. Чертёж один, но кораблей много. Корабли разные, у них разные имена, они возят разные грузы. Но они очень похожие: они все — корабли с идентичной конструкцией, и могут выполнять аналогичные задачи.

— На примере кораблей все понятно. А можно еще пару аналогий, чтобы я точно понял, о чем речь?

— Хотя нет, что-то с пчелами у меня плохие ассоциации. Возьмем лучше муравейник.

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

— Это просто идеальный пример. В типичной программе все точно так же. Есть главный объект, который создаёт объекты всех остальных классов. Объекты начинают взаимодействовать друг с другом и «внешним миром» программы. Внутри этих объектов жёстко запрограммировано их поведение.

— Не совсем понятно. Вернее, совсем не понятно.

— Два этих пояснения – это две стороны одной медали. Истина посередине. Первый пример (про чертеж и корабли) показывает связь между классом и объектами этого класса. Аналогия очень сильная. Второй пример (про муравейник) показывает связь между объектами, которые существуют во время работы программы, и написанными классами.

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

— Да, но это легче чем кажется. В Java все сущности во время работы программы являются объектами, а написание программы сводится к описанию различных способов взаимодействия объектов. Объекты просто вызывают методы друг друга и передают в них нужные данные.

— Не совсем очевидно, но почти понятно.

— А как узнать, какие методы вызывать, и какие данные туда передавать?

— У каждого класса есть описание, в котором говорится – для чего он создан. Также и у каждого его метода есть описание: что он делает, и какие данные нужно в него передавать. Чтобы использовать класс, нужно в общих чертах знать, что он делает. А также нужно точно знать, что делает каждый его метод. И совсем не обязательно знать, как он это делает . Такая себе волшебная палочка.

— Вот посмотри на код класса, который копирует файл:

package com.javarush.lesson2; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; public class FileCopy < public static void main(String[] args) throws IOException < FileInputStream fileInputStream = new FileInputStream("c:\\data.txt"); FileOutputStream fileOutputStream = new FileOutputStream("c:\\result.txt"); while (fileInputStream.available() > 0) < int data = fileInputStream.read(); fileOutputStream.write(data); > fileInputStream.close(); fileOutputStream.close(); > >

— Не то, чтобы все понятно, но суть уже улавливаю.

— Отлично. Тогда – до следующего урока.

— Чуть не забыла. Вот тебе задачка от Диего.

Источник

Оцените статью