Патерн (шаблон) проектування composite (компоновщик)

Призначення паттерна Composite

Використовуйте патерн Composite якщо:

  • Необхідно об'єднувати групи схожих об'єктів і управляти ними.
  • Об'єкти можуть бути як примітивними (елементарними), так і складовими (складними). Складений об'єкт може включати в себе колекції інших об'єктів, утворюючи складні деревовидні структури. Приклад: директорія файлової системи складається з елементів, кожен з яких також може бути Директорією.
  • Код клієнта працює з примітивними і складовими об'єктами одноманітно.

Опис паттерна Composite

Управління групами об'єктів може бути непростим завданням, особливо, якщо ці об'єкти містять власні об'єкти.

Для військової стратегічної гри "Пунічні війни", яка описує військове протистояння між Римом і Карфагеном (див. Розділ Що породжують патерни), кожна бойова одиниця (вершник, лучник, піхотинець) має свою власну руйнує силу. Ці одиниці можуть об'єднуватися в групи для утворення більш складних військових підрозділів, наприклад, римські легіони, які, в свою чергу, об'єднуючись, утворюють цілу армію. Як розрахувати бойову міць таких ієрархічних з'єднань?

Патерн Composite пропонує наступне рішення. Він вводить абстрактний базовий клас Component з поведінкою, загальним для всіх примітивних і складових об'єктів. Для випадку стратегічної гри - це метод getStrength () для підрахунку руйнує сили. Підкласи Primitive and Composite є похідними від класу Component. Складений об'єкт Composite зберігає компоненти-нащадки абстрактного типу Component. кожен з яких може бути також Composite.

UML-діаграма класів паттерна Composite

Патерн (шаблон) проектування composite (компоновщик)

Для додавання або видалення об'єктів-нащадків у складений об'єкт Composite. клас Component визначає інтерфейси add () і remove ().

Реалізація патерну Composite

Застосуємо патерн Composite для нашої стратегічної гри. Спочатку сформуємо різні військові з'єднання римської армії, а потім розрахуємо руйнує силу.

Слід звернути увагу на один важливий момент. Абстрактний базовий клас Unit оголошує інтерфейс для додавання нових бойових одиниць addUnit (), незважаючи на те, що об'єктам примітивних типів (Archer. Infantryman. Horseman) подібна операція не потрібна. Зроблено це на догоду прозорості системи на шкоду її безпеки. Клієнт знає, що об'єкт типу Unit завжди буде мати метод addUnit (). Однак його виклик для примітивних об'єктів вважається помилковим і небезпечним.

Можна зробити систему більш безпечною, перемістивши метод addUnit () в складений об'єкт CompositeUnit. Однак при цьому виникає наступна проблема: ми не знаємо, чи містить об'єкт Unit метод addUnit ().

Розглянемо наступний фрагмент коду.

В абстрактному класі-Unit з'явився новий віртуальний метод getComposite () з реалізацією за замовчуванням, яка повертає 0. Клас CompositeUnit переопределяет цей метод, повертаючи покажчик на самого себе. Завдяки цьому методу можна запросити у компонента його тип. Якщо він складовою, то можна застосувати операцію addUnit ().

Результати застосування патерну Composite

Переваги паттерна Composite

  • В систему легко додавати нові примітивні або складові об'єкти, так як патерн Composite використовує загальний базовий клас Component.
  • Код клієнта має просту структуру - примітивні і складові елементи обробляються однаковим чином.
  • Патерн Composite дозволяє легко обійти всі вузли деревовидної структури

Недоліки паттерна Composite

  • Незручно здійснити заборона на додавання в складений об'єкт Composite об'єктів певних типів. Так, наприклад, до складу римської армії не можуть входити бойові слони.

Схожі статті