Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
# Где применять ассоциацию (Association) в Java
Ассоциация — это отношение между классами, которое указывает, что один класс использует или работает с другим классом. Это один из четырёх типов отношений в UML (наряду с агрегацией, композицией и наследованием).
Типы ассоциаций
1. Простая ассоциация (Association)
Один класс ссылается на другой, но не владеет его жизненным циклом:
public class Driver {
private Car car; // Ассоциация: водитель может водить разные машины
public void setCar(Car car) {
this.car = car;
}
public void drive() {
System.out.println("Driving " + car.getModel());
}
}
public class Car {
private String model;
public Car(String model) {
this.model = model;
}
public String getModel() {
return model;
}
}
// Использование
Driver driver = new Driver();
Car car1 = new Car("BMW");
Car car2 = new Car("Mercedes");
driver.setCar(car1);
driver.drive(); // Driving BMW
driver.setCar(car2); // Водитель может менять машину
driver.drive(); // Driving Mercedes
2. Агрегация (Aggregation)
Один класс содержит другой, но не владеет его жизненным циклом (has-a):
public class Library {
private List<Book> books; // Агрегация
public Library() {
this.books = new ArrayList<>();
}
public void addBook(Book book) {
books.add(book);
}
public void removeBook(Book book) {
books.remove(book);
}
}
public class Book {
private String title;
public Book(String title) {
this.title = title;
}
}
// Использование
Book book1 = new Book("Clean Code");
Book book2 = new Book("Design Patterns");
Library library = new Library();
library.addBook(book1);
library.addBook(book2);
// Если библиотека закроется, книги остаются (не их жизненный цикл)
3. Композиция (Composition)
Один класс владеет другим (strong ownership), жизненные циклы связаны:
public class House {
private List<Room> rooms; // Композиция: комнаты принадлежат дому
public House() {
this.rooms = new ArrayList<>();
// Создаём комнаты как часть дома
rooms.add(new Room("Kitchen"));
rooms.add(new Room("Bedroom"));
}
public void demolish() {
// Удаляя дом, удаляем и комнаты
rooms.clear();
}
}
public class Room {
private String name;
public Room(String name) {
this.name = name;
}
}
// Использование
House house = new House(); // Создаём дом -> комнаты автоматически создаются
house.demolish(); // Разрушаем дом -> комнаты исчезают
Где применять каждую ассоциацию
Применять простую ассоциацию
Когда:
- Классы не зависят друг от друга в плане жизненного цикла
- Один объект может взаимодействовать с несколькими другими
- Отношение слабое и может быть изменено в runtime
Примеры:
// Student может быть в разных Group
public class Student {
private String name;
private Group currentGroup; // Ассоциация
public void switchGroup(Group newGroup) {
this.currentGroup = newGroup; // Легко менять
}
}
public class Group {
private String name;
}
// Manager может управлять разными Team
public class Manager {
private List<Team> teams; // Ассоциация
public void addTeam(Team team) {
teams.add(team);
}
}
public class Team {
private String name;
}
// User может иметь разные Permission
public class User {
private String email;
private List<Permission> permissions; // Ассоциация
public void grantPermission(Permission perm) {
permissions.add(perm);
}
}
public class Permission {
private String name;
}
Применять агрегацию
Когда:
- Один класс содержит коллекцию других объектов
- Содержащий класс не отвечает за создание/удаление элементов
- Элементы могут существовать независимо
- Отношение типа "has-a"
Примеры:
// Project содержит Task, но Task может существовать отдельно
public class Project {
private String name;
private List<Task> tasks; // Агрегация
public void addTask(Task task) {
tasks.add(task);
}
}
public class Task {
private String description;
private boolean completed;
}
// Playlist содержит Song
public class Playlist {
private String name;
private List<Song> songs; // Агрегация
public void addSong(Song song) {
songs.add(song);
}
}
public class Song {
private String title;
private String artist;
}
// Department содержит Employee
public class Department {
private String name;
private List<Employee> employees; // Агрегация
public void hireEmployee(Employee emp) {
employees.add(emp);
}
public void fireEmployee(Employee emp) {
employees.remove(emp);
// Employee может найти другую работу
}
}
public class Employee {
private String name;
private double salary;
}
Применять композицию
Когда:
- Один класс владеет частями другого класса
- Части не могут существовать без целого
- Жизненные циклы тесно связаны
- "has-a" с сильной связью
Примеры:
// Car содержит Engine (не может быть без Engine)
public class Car {
private Engine engine; // Композиция
private Wheel[] wheels; // Композиция
public Car() {
this.engine = new Engine(); // Создаём части в конструкторе
this.wheels = new Wheel[4];
for (int i = 0; i < 4; i++) {
wheels[i] = new Wheel();
}
}
public void start() {
engine.start(); // Используем части
}
}
public class Engine {
public void start() {
System.out.println("Engine started");
}
}
public class Wheel {
private int diameter = 16;
}
// Computer содержит RAM, HDD (не могут быть отдельно)
public class Computer {
private RAM ram; // Композиция
private HDD hdd; // Композиция
private CPU cpu; // Композиция
public Computer(int ramSize, int hddSize) {
this.ram = new RAM(ramSize);
this.hdd = new HDD(hddSize);
this.cpu = new CPU();
}
public void shutdown() {
// Компьютер и его компоненты удаляются вместе
}
}
// Order содержит OrderItem (товары в заказе)
public class Order {
private Long id;
private List<OrderItem> items; // Композиция
public Order() {
this.items = new ArrayList<>();
}
public void addItem(String productName, int quantity) {
items.add(new OrderItem(productName, quantity));
}
public double getTotalPrice() {
return items.stream()
.mapToDouble(OrderItem::getPrice)
.sum();
}
}
public class OrderItem {
private String productName;
private int quantity;
private double price;
}
Сравнительная таблица
| Характеристика | Ассоциация | Агрегация | Композиция |
|---|---|---|---|
| Сила связи | Слабая | Средняя | Сильная |
| Владение | Нет | Слабое | Полное |
| Жизненные циклы | Независимые | Независимые | Связанные |
| Направление | Может быть двусторонней | Односторонняя | Односторонняя |
| Когда создаётся | Может быть любое время | Может быть любое время | При создании владельца |
| Когда удаляется | Независимо | Независимо | Вместе с владельцем |
| Примеры | Driver-Car, Teacher-Student | Library-Book, Team-Member | Car-Engine, House-Room |
Best Practices
1. Prefer Composition over Inheritance
// Плохо: наследование
public class PoweredCar extends Car {
// Наследуем всё, даже не нужное
}
// Хорошо: композиция
public class Car {
private Engine engine; // Композиция
private List<Wheel> wheels; // Композиция
public void start() {
engine.start();
}
}
2. Используй setter для ассоциации, constructor для композиции
// Ассоциация: setter
public class Manager {
private Team team;
public void setTeam(Team team) { // Может менять
this.team = team;
}
}
// Композиция: constructor
public class Car {
private final Engine engine; // final — не может менять
public Car() {
this.engine = new Engine(); // Создаём в constructor
}
}
3. Избегай циклических ассоциаций
// Плохо: циклическая ассоциация
public class Parent {
private List<Child> children;
// Если добавить: private Parent parent; — циклическая ссылка
}
// Хорошо: только в одну сторону
public class Parent {
private List<Child> children;
}
public class Child {
// Ссылка на родителя, если нужна
private Parent parent; // Но обычно используют ID
}
Практический пример: E-commerce System
// Композиция: Order содержит OrderItems
public class Order {
private Long id;
private LocalDateTime createdAt;
private List<OrderItem> items; // Композиция
public Order() {
this.items = new ArrayList<>();
}
}
public class OrderItem {
private Long id;
private Product product;
private int quantity;
}
// Агрегация: Warehouse содержит Stock
public class Warehouse {
private String location;
private List<Stock> stocks; // Агрегация
public void addStock(Stock stock) {
stocks.add(stock);
}
}
public class Stock {
private Product product;
private int quantity;
}
// Ассоциация: Seller может продавать разные Product
public class Seller {
private String name;
private List<Product> products; // Ассоциация
public void listProduct(Product product) {
products.add(product);
}
}
public class Product {
private Long id;
private String name;
private double price;
}
Выводы
- Ассоциация — для слабых, изменяемых отношений
- Агрегация — для контейнеров со слабой связью
- Композиция — для сильных, неразлучных отношений
- Правило: Prefer composition over inheritance
- На практике: Большинство случаев — это просто ассоциация или композиция
Правильное использование ассоциаций делает код гибким, тестируемым и поддерживаемым.