Skip to content

Композиция в контексте ООП

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. Типичные ошибки

  1. Создание слишком сильных связей между компонентами
  2. Нарушение инкапсуляции
  3. Неправильное управление жизненным циклом
  4. Избыточное использование композиции
  5. Смешивание композиции и агрегации

9. Практические рекомендации

  1. Начинать с композиции вместо наследования
  2. Использовать интерфейсы для компонентов
  3. Соблюдать принцип инверсии зависимостей
  4. Обеспечивать корректную обработку ошибок
  5. Документировать отношения между классами

практика

[[Programming/java/1. osnovi/Тема 5. Интерфейсы, абстрактные классы, статические методы/Урок 4. Композиция в контексте ООП/задача|задача]]