You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Демонстрация паттерна Composite (Компоновщик) на примере тактической RPG системы отрядов и армий.
🎯 Описание паттерна
Composite — структурный паттерн проектирования, который позволяет сгруппировать объекты в древовидную структуру, а затем работать с ними так, как будто это единичный объект.
Когда использовать:
Ситуация
Пример в играх
Объекты могут содержать другие объекты
Отряд → юниты
Клиент не должен различать простые и составные объекты
Приказ атаки для одного юнита и для целой армии
Нужна иерархическая структура
Дерево навыков, система папок файлов, UI компоненты
Армия (Group)
├── Отряд "Мечники" (Group)
│ ├── Рыцарь (Unit, 100 HP)
│ ├── Солдат (Unit, 80 HP)
│ └── Солдат (Unit, 80 HP)
├── Отряд "Лучники" (Group)
│ ├── Лучник (Unit, 60 HP)
│ ├── Лучник (Unit, 60 HP)
│ └── Маг (Unit, 50 HP)
└── Герой "Паладин" (Unit, 150 HP)
📁 Структура проекта
PatternComposite/
│
├── Composite/
│ ├── IGameEntity.cs # Интерфейс для всех игровых сущностей
│ ├── Unit.cs # Листовой элемент (один юнит)
│ └── Group.cs # Контейнер (группа/отряд/армия)
├── Program.cs # Точка входа и демонстрация
└── README.md # Этот файл
Описание классов
Класс/Интерфейс
Роль в паттерне
Описание
IGameEntity
Component
Определяет общий интерфейс для всех элементов
Unit
Leaf
Листовой элемент, не может содержать других элементов
Group
Composite
Контейнер, может содержать другие IGameEntity
Program
Client
Работает с объектами через общий интерфейс
💻 Пример использования
// Создаем отрядыGroupswordsmen=newGroup();swordsmen.Add(newUnit("Рыцарь",100));swordsmen.Add(newUnit("Солдат",80));Grouparchers=newGroup();archers.Add(newUnit("Лучник",60));archers.Add(newUnit("Маг",50));// Создаем армию и добавляем в нее отрядыGrouparmy=newGroup();army.Add(swordsmen);army.Add(archers);// Наносим урон по всей армии (рекурсивно)army.TakeDamage(30);// Получаем общее здоровьеinttotalHealth=army.GetTotalHealth();
Пример вывода
Общее здоровье армии: 370
Наносим 30 урона по всей армии:
Юнит Рыцарь получил 30 урона. Осталось здоровья: 70
Юнит Солдат получил 30 урона. Осталось здоровья: 50
Юнит Лучник получил 30 урона. Осталось здоровья: 30
Юнит Маг получил 30 урона. Осталось здоровья: 20
Общее здоровье армии: 170
🚀 Расширение паттерна
1. Добавление новых типов урона (Strategy + Composite)
publicenumDamageType{Physical,Fire,Ice,Poison}publicinterfaceIGameEntity{voidTakeDamage(intdamage,DamageTypetype=DamageType.Physical);intGetTotalHealth();}// Unit.cspublicvoidTakeDamage(intdamage,DamageTypetype){intactualDamage=typeswitch{DamageType.Fire=>damage*2,// Уязвимость к огнюDamageType.Ice=>damage/2,// Сопротивление холоду
_ =>damage};Health=Math.Max(0,Health-actualDamage);}
publicinterfaceIGameEntityVisitor{voidVisit(Unitunit);voidVisit(Groupgroup);}publicclassHealVisitor:IGameEntityVisitor{privatereadonlyint_healAmount;publicHealVisitor(inthealAmount)=>_healAmount=healAmount;publicvoidVisit(Unitunit)=>unit.Heal(_healAmount);publicvoidVisit(Groupgroup){}// Группа обрабатывается отдельно}// В классе GrouppublicvoidAccept(IGameEntityVisitorvisitor){visitor.Visit(this);foreach(varentityin_entities){if(entityisUnitunit)visitor.Visit(unit);elseif(entityisGroupgroup)group.Accept(visitor);}}