Композиция в контексте ООП
1. Определение композиции
- Композиция - это особый вид отношения между классами, где один класс содержит другой
- Отношение "часть-целое" или "имеет" (has-a)
- Жизненный цикл части зависит от жизненного цикла целого
- Часть не может существовать без целого
2. Композиция vs Агрегация
2.1 Композиция
- Сильная связь между объектами
- Часть существует только в составе целого
- При уничтожении целого уничтожаются все его части
- Часть не может принадлежать другому целому
2.2 Агрегация
- Более слабая связь
- Части могут существовать независимо от целого
- При уничтожении целого части могут продолжать существовать
- Часть может принадлежать нескольким целым
3. Реализация композиции в Java
3.1 Простой пример композиции
// Часть
class Engine {
private String type;
private int power;
public Engine(String type, int power) {
this.type = type;
this.power = power;
}
public void start() {
System.out.println("Engine started");
}
}
// Целое
class Car {
private final Engine engine; // Композиция
private String model;
public Car(String model, String engineType, int enginePower) {
this.model = model;
this.engine = new Engine(engineType, enginePower); // Создание части внутри целого
}
public void startCar() {
engine.start();
System.out.println("Car is ready to go");
}
}
3.2 Более сложный пример
class Computer {
private final Motherboard motherboard;
private final Processor processor;
private final Memory memory;
private final Storage storage;
public Computer(String model) {
this.motherboard = new Motherboard("ATX");
this.processor = new Processor("Intel i7");
this.memory = new Memory(16);
this.storage = new Storage(1000);
assembleComponents();
}
private void assembleComponents() {
motherboard.installProcessor(processor);
motherboard.installMemory(memory);
motherboard.connectStorage(storage);
}
public void turnOn() {
motherboard.powerOn();
}
}
4. Преимущества композиции
4.1 Инкапсуляция
- Внутренняя реализация компонентов скрыта
- Изменения в компонентах не влияют на внешний интерфейс
- Улучшенная безопасность данных
4.2 Гибкость
- Легко заменять реализации компонентов
- Возможность изменения поведения во время выполнения
- Более простое тестирование
4.3 Повторное использование кода
- Компоненты могут быть переиспользованы в других классах
- Уменьшение дублирования кода
- Улучшенная модульность
5. Практические примеры использования
5.1 Графический интерфейс
class Window {
private final Header header;
private final Body body;
private final Footer footer;
public Window() {
this.header = new Header();
this.body = new Body();
this.footer = new Footer();
}
public void render() {
header.display();
body.display();
footer.display();
}
}
5.2 Банковская система
class BankAccount {
private final AccountDetails details;
private final TransactionHistory history;
private final SecurityModule security;
public BankAccount(String accountNumber, String ownerName) {
this.details = new AccountDetails(accountNumber, ownerName);
this.history = new TransactionHistory();
this.security = new SecurityModule(accountNumber);
}
public void makeTransaction(Transaction transaction) {
if (security.validateTransaction(transaction)) {
history.addTransaction(transaction);
details.updateBalance(transaction.getAmount());
}
}
}
6. Лучшие практики
6.1 Проектирование
- Использовать final для полей композиции
- Создавать компоненты в конструкторе
- Обеспечивать корректную инициализацию всех компонентов
- Соблюдать принцип единственной ответственности
6.2 Управление жизненным циклом
- Правильно освобождать ресурсы
- Обрабатывать исключения при создании компонентов
- Обеспечивать потокобезопасность при необходимости
7. Композиция vs Наследование
7.1 Когда использовать композицию
- Когда нужна гибкость в изменении поведения
- Когда компоненты могут меняться во время выполнения
- Когда требуется использование нескольких функциональностей
- Когда нет истинного отношения "является" (is-a)
7.2 Преимущества перед наследованием
- Меньшая связанность кода
- Более простое тестирование
- Лучшая инкапсуляция
- Возможность изменения поведения во время выполнения
- Избегание проблем множественного наследования
8. Типичные ошибки
- Создание слишком сильных связей между компонентами
- Нарушение инкапсуляции
- Неправильное управление жизненным циклом
- Избыточное использование композиции
- Смешивание композиции и агрегации
9. Практические рекомендации
- Начинать с композиции вместо наследования
- Использовать интерфейсы для компонентов
- Соблюдать принцип инверсии зависимостей
- Обеспечивать корректную обработку ошибок
- Документировать отношения между классами
практика
[[Programming/java/1. osnovi/Тема 5. Интерфейсы, абстрактные классы, статические методы/Урок 4. Композиция в контексте ООП/задача|задача]]