← Назад к вопросам

Приведи пример агрегации

1.8 Middle🔥 161 комментариев
#Базы данных (SQL)

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Агрегация в объектно-ориентированном программировании

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

Концепция агрегации

Агрегация (Has-A отношение) означает, что один объект содержит другой объект, но:

  • Объект-часть может существовать отдельно
  • Удаление контейнера не удаляет части
  • Связь слабая (one-way)
Автомобиль → Двигатель

Если удалить автомобиль, двигатель может быть переиспользован!

Пример 1: Команда проекта

Практический пример — команда разработки:

from typing import List
from datetime import datetime

class Developer:
    def __init__(self, name: str, experience: int):
        self.name = name
        self.experience = experience
        self.projects = []  # Разработчик может работать над несколькими проектами
    
    def __repr__(self):
        return f"Developer({self.name}, {self.experience}y)"

class Project:
    def __init__(self, name: str):
        self.name = name
        self.developers: List[Developer] = []  # АГРЕГАЦИЯ!
        self.created_at = datetime.now()
    
    def add_developer(self, developer: Developer):
        """Добавить разработчика в проект"""
        self.developers.append(developer)
        developer.projects.append(self)
    
    def remove_developer(self, developer: Developer):
        """Удалить разработчика из проекта"""
        self.developers.remove(developer)
        developer.projects.remove(self)
    
    def __repr__(self):
        return f"Project({self.name}, {len(self.developers)} devs)"

# Использование
dev1 = Developer("Alice", 5)
dev2 = Developer("Bob", 3)

project = Project("BackendAPI")
project.add_developer(dev1)
project.add_developer(dev2)

print(project)  # Project(BackendAPI, 2 devs)
print(dev1.projects)  # [Project(BackendAPI, 2 devs)]

# Удаляем проект
del project

# Разработчики всё ещё существуют!
print(dev1)  # Developer(Alice, 5y)
print(dev1.projects)  # []

Ключевое отличие: Агрегация vs Композиция

Агрегация — слабая связь:

class Library:  # Библиотека
    def __init__(self, name: str):
        self.name = name
        self.books = []  # Список книг (существующих отдельно)
    
    def add_book(self, book: 'Book'):
        self.books.append(book)

class Book:
    def __init__(self, title: str):
        self.title = title

# Создаём книги отдельно
book1 = Book("Python Guide")
book2 = Book("Design Patterns")

# Добавляем в библиотеку
library = Library("City Library")
library.add_book(book1)
library.add_book(book2)

# Удаляем библиотеку
del library

# Книги всё ещё существуют!
print(book1.title)  # "Python Guide"

# АГРЕГАЦИЯ: library → books (слабая связь)

Композиция — сильная связь:

class Car:  # Автомобиль
    def __init__(self, model: str):
        self.model = model
        # Двигатель создан с автомобилем
        self.engine = Engine("V8")  # Создаём ВНУТРИ
        self.wheels = [Wheel() for _ in range(4)]  # Создаём ВНУТРИ
    
    def __del__(self):
        # Удаляем двигатель и колёса вместе с машиной
        print(f"Car {self.model} destroyed with engine and wheels")

class Engine:
    def __init__(self, type: str):
        self.type = type

class Wheel:
    def __init__(self):
        self.diameter = 17

car = Car("Tesla")
# Двигатель создан вместе с автомобилем

del car  # Удаляем машину
# Удаляется и двигатель! (Car destroyed with engine and wheels)

# КОМПОЗИЦИЯ: car → engine (сильная связь)
# Двигатель не может существовать без машины

Пример 2: Школа и учителя

class Teacher:
    def __init__(self, name: str, subject: str):
        self.name = name
        self.subject = subject
        self.schools = []  # Учитель может работать в несколько школ
    
    def __repr__(self):
        return f"Teacher({self.name}, {self.subject})"

class School:
    def __init__(self, name: str):
        self.name = name
        self.teachers: List[Teacher] = []  # Список учителей (АГРЕГАЦИЯ)
        self.students: List['Student'] = []  # Студенты создаются в школе
    
    def hire_teacher(self, teacher: Teacher):
        """Нанять учителя (агрегация)"""
        self.teachers.append(teacher)
        teacher.schools.append(self)
    
    def fire_teacher(self, teacher: Teacher):
        """Уволить учителя (агрегация)"""
        self.teachers.remove(teacher)
        teacher.schools.remove(self)
    
    def enroll_student(self, name: str) -> 'Student':
        """Зачислить студента (композиция)"""
        student = Student(name, self)
        self.students.append(student)
        return student

class Student:
    def __init__(self, name: str, school: School):
        self.name = name
        self.school = school  # Студент привязан к школе
    
    def __repr__(self):
        return f"Student({self.name}, {self.school.name})"

# Создаём учителей отдельно
teacher1 = Teacher("John", "Math")
teacher2 = Teacher("Jane", "Physics")

# Создаём школу
school = School("MIT")

# Нанимаем учителей
school.hire_teacher(teacher1)
school.hire_teacher(teacher2)

# Зачисляем студентов
student1 = school.enroll_student("Alice")
student2 = school.enroll_student("Bob")

print(school.teachers)  # [Teacher(John, Math), Teacher(Jane, Physics)]
print(school.students)  # [Student(Alice, MIT), Student(Bob, MIT)]

# Закрываем школу
del school

# Учителя всё ещё существуют (агрегация!)
print(teacher1)  # Teacher(John, Math)
print(teacher1.schools)  # [] (школы удалены)

# Студенты удалены (композиция!)
print(student1.school)  # AttributeError или None

Пример 3: Компания с отделами

from enum import Enum
from typing import List

class DepartmentType(Enum):
    ENGINEERING = "Engineering"
    SALES = "Sales"
    SUPPORT = "Support"

class Employee:
    def __init__(self, name: str, salary: float):
        self.name = name
        self.salary = salary
        self.department = None  # Сотрудник может переходить между отделами
    
    def __repr__(self):
        return f"Employee({self.name}, ${self.salary})"

class Department:
    def __init__(self, dept_type: DepartmentType):
        self.type = dept_type
        self.employees: List[Employee] = []  # АГРЕГАЦИЯ
    
    def hire_employee(self, employee: Employee):
        if employee.department:
            # Сотрудник переходит из другого отдела
            employee.department.employees.remove(employee)
        
        self.employees.append(employee)
        employee.department = self
    
    def get_total_salary(self) -> float:
        return sum(emp.salary for emp in self.employees)
    
    def __repr__(self):
        return f"Department({self.type.value}, {len(self.employees)} employees)"

class Company:
    def __init__(self, name: str):
        self.name = name
        self.departments: List[Department] = []  # Отделы существуют с компанией
    
    def add_department(self, dept_type: DepartmentType) -> Department:
        """Создать отдел"""
        dept = Department(dept_type)
        self.departments.append(dept)
        return dept

# Создаём компанию
company = Company("TechCorp")

# Создаём отделы
eng_dept = company.add_department(DepartmentType.ENGINEERING)
sales_dept = company.add_department(DepartmentType.SALES)

# Создаём сотрудников
alice = Employee("Alice", 100000)
bob = Employee("Bob", 80000)
charlie = Employee("Charlie", 90000)

# Нанимаем в инженерию
eng_dept.hire_employee(alice)
eng_dept.hire_employee(bob)

# Нанимаем в продажи
sales_dept.hire_employee(charlie)

print(company.name)  # TechCorp
print(eng_dept)  # Department(Engineering, 2 employees)
print(eng_dept.get_total_salary())  # 180000

# Перевод сотрудника
eng_dept.hire_employee(charlie)  # charlie переходит в инженерию

print(eng_dept)  # Department(Engineering, 3 employees)
print(sales_dept)  # Department(Sales, 0 employees)

# Удаляем компанию
del company

# Сотрудники всё ещё существуют!
print(alice)  # Employee(Alice, 100000)
print(alice.department)  # None (связь разорвана)

Пример 4: Real World — Микросервис архитектура

from abc import ABC, abstractmethod
from typing import List

class Service(ABC):
    def __init__(self, name: str):
        self.name = name
    
    @abstractmethod
    def start(self):
        pass
    
    @abstractmethod
    def stop(self):
        pass

class UserService(Service):
    def start(self):
        print(f"{self.name} started")
    
    def stop(self):
        print(f"{self.name} stopped")

class PaymentService(Service):
    def start(self):
        print(f"{self.name} started")
    
    def stop(self):
        print(f"{self.name} stopped")

class ApiGateway:
    def __init__(self):
        self.services: List[Service] = []  # АГРЕГАЦИЯ
    
    def register_service(self, service: Service):
        """Зарегистрировать сервис (внешний)"""
        self.services.append(service)
    
    def start_all(self):
        for service in self.services:
            service.start()
    
    def stop_all(self):
        for service in self.services:
            service.stop()

# Создаём независимые сервисы
user_service = UserService("UserService")
payment_service = PaymentService("PaymentService")

# Регистрируем в gateway
gateway = ApiGateway()
gateway.register_service(user_service)
gateway.register_service(payment_service)

gateway.start_all()
# Output:
# UserService started
# PaymentService started

# Удаляем gateway
del gateway

# Сервисы продолжают работать!
user_service.start()  # UserService started

Диаграмма: Агрегация vs Композиция

АГРЕГАЦИЯ (Whole ◇ Part)
┌──────────────────────────────────┐
│ School (Целое)       ◇──── Teacher │
│                      ◇──── Teacher │
│                      ◇──── Teacher │
└──────────────────────────────────┘

Учителя существуют отдельно
Могут работать в разных школах
Удаление школы НЕ удаляет учителей


КОМПОЗИЦИЯ (Whole ● Part)
┌────────────────────┐
│ Car (Целое)   ● Engine │
│              ● Wheels │
│              ● Seats  │
└────────────────────┘

Части существуют ТОЛЬКО в целом
Не могут существовать отдельно
Удаление машины УДАЛЯЕТ все части

Практические правила

# АГРЕГАЦИЯ используется когда:
# 1. Part может существовать независимо
# 2. Несколько Whole могут использовать один Part
# 3. Part имеет свой жизненный цикл

class Library:
    def __init__(self):
        self.books = []  # Книги существуют отдельно

class Book:
    def __init__(self, title):
        self.title = title
        # Книга не привязана к библиотеке

# КОМПОЗИЦИЯ используется когда:
# 1. Part не может существовать без Whole
# 2. Только один Whole владеет Part
# 3. Part создаётся и удаляется с Whole

class Document:
    def __init__(self):
        self.header = Header()  # Header существует ТОЛЬКО в Document
        self.body = Body()      # Body существует ТОЛЬКО в Document
        self.footer = Footer()  # Footer существует ТОЛЬКО в Document

class Header: pass
class Body: pass
class Footer: pass

Заключение

Агрегация — это тип связи, где:

  • Объект содержит другой объект
  • Части существуют отдельно от целого
  • Удаление целого не удаляет части
  • Это слабая связь (Has-A)

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