Комментарии (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)
Агрегация отличается от композиции тем, что жизненные циклы объектов независимы. Это один из самых полезных паттернов в объектно-ориентированном программировании для создания гибких и переиспользуемых систем.