Паттерн Компоновщик объединяет объекты в древовидные структуры для представления иерархий часть\целое. Компоновщик позволяет клиенту выполнять однородные операции сами отдельными объектами и их совокупностями.
Паттерн Компоновщик позволяет клиенту выполнять однородные операции с комбинациями и отдельными объектами.
Паттерн Компоновщик предоставляет структуру для хранения как отдельных объектов, так и комбинаций.
В реализации паттерна Компоновщик приходится искать баланс между прозрачностью, безопасностью и вашими потребностями.
Рассмотрим пример, в котором нам надо реализовать меню для интерактивного автомата в одной из кафешек.
У нас имеются отдельные классы завтрака и обеда, с набором каких-то блюд. Когда клиент подходит к автомату, он выбирает блюда для завтрака или обеда, но часто бывает такое что в обед могут входить блюда из завтрака. А также дополнятся новыми блюдами сегодняшнего дня. Представляете сложность иерархии построения такой логики программы, когда каждый день придется вносить еще какие-то правки? Вот тут и приходит к нам на помощь Паттерн Компоновщик, который поможет создать древовидное меню блюд, и выводить всю информацию о них.
using System;
using System.Collections;
namespace Паттерн_Компоновщик
{
// Базовый класс Компонент объявляет общие операции как для простых, так и
// для сложных объектов структуры.
public abstract class MenuComponent
{
public virtual void Add(MenuComponent menuComponent)
{
throw new NotImplementedException();
}
public virtual void Remove(MenuComponent menu)
{
throw new NotImplementedException();
}
public virtual MenuComponent GetChild(int i)
{
throw new NotImplementedException();
}
public virtual double GetPrice()
{
throw new NotImplementedException();
}
public virtual bool IsVegetarian()
{
throw new NotImplementedException();
}
public virtual void Print()
{
throw new NotImplementedException();
}
}
public class MenuItem:MenuComponent
{
public string Name { get; }
public string Description { get; }
public bool Vegetarian { get; }
public double Price { get; }
public MenuItem(string name, string description, bool vegetarian, double price)
{
this.Name = name;
this.Description = description;
this.Vegetarian = vegetarian;
this.Price = price;
}
public override bool IsVegetarian()
{
return Vegetarian;
}
public override void Print()
{
Console.Write(" "+Name);
if (IsVegetarian())
{
Console.Write("(v)");
}
Console.WriteLine(", "+Price);
Console.WriteLine(" --"+Description);
}
public override void Add(MenuComponent menuComponent)
{
throw new NotImplementedException();
}
}
public class Menu : MenuComponent
{
ArrayList menuComponents = new ArrayList();
public string Name { get; set; }
public string Description { get; set; }
public Menu(string name, string description)
{
this.Name = name;
this.Description = description;
}
public override void Add(MenuComponent menuComponent)
{
menuComponents.Add(menuComponent);
}
public override void Remove(MenuComponent menuComponent)
{
menuComponents.Remove(menuComponent);
}
public override MenuComponent GetChild(int i)
{
return (MenuComponent)menuComponents[i];
}
public override void Print()
{
Console.Write("\n"+Name);
Console.WriteLine(", "+Description);
Console.WriteLine("--------------------");
//Используем итератор для перебора всех компонентов объекта Меню
IEnumerator iterator = menuComponents.GetEnumerator();
while (iterator.MoveNext())
{
MenuComponent menuComponent = (MenuComponent)iterator.Current;
menuComponent.Print();
}
}
}
public class DinnerMenu : Menu
{
public DinnerMenu(string name, string description) : base(name, description)
{
base.Add(new MenuItem("Манная каша", "Манная каша на миндальном молоке с ванилью", true, 120));
base.Add(new MenuItem("Чечевичный суп", "Чечевичный суп с томатами", true, 150));
base.Add(new MenuItem("Суп рассольник", "Постный рассольник", true, 180));
base.Add(new MenuItem("Фаршированные перцы", "Фаршированные перцы с грибами и кабачком", true, 230));
base.Add(new MenuItem("Овощное рагу", "Овощное рагу с мясом", false, 350));
base.Add(new MenuItem("Свинина", "Свинина под лимонной заправкой", false, 550));
}
}
public class BreakfastMenu : Menu
{
public BreakfastMenu(string name, string description):base(name,description)
{
base.Add(new MenuItem("Блиный гурман", "Блинчики со взбитыми яцами и тостом", true, 130));
base.Add(new MenuItem("Блиный гурман", "Блинчики со взбитыми яцами и тостом", true, 130));
base.Add(new MenuItem("Обычны завтра из блинов", "Жареный блин с сосиской", true, 130));
base.Add(new MenuItem("Блины с черникой", "Блины со свежей черникой", true, 230));
base.Add(new MenuItem("Фруктовые блины", "Блины со свежей черникой и клубникой", true, 230));
}
}
public class Automatic
{
MenuComponent allMenus;
public Automatic(MenuComponent allMenus)
{
this.allMenus = allMenus;
}
public void PrintMenu()
{
allMenus.Print();
}
}
class Program
{
static void Main(string[] args)
{
MenuComponent breakfastMenu = new BreakfastMenu("Меню завтрак", "Завтрак");
MenuComponent dinnerMenu = new DinnerMenu("Меню обеда", "Обед");
MenuComponent allMenus = new Menu("Все меню","Общее меню");
allMenus.Add(breakfastMenu);
allMenus.Add(dinnerMenu);
dinnerMenu.Add(new MenuItem("Паста", "Спагетти с соусом маринада и ломтик хлеба на закваске", true, 140));
dinnerMenu.Add(breakfastMenu); //В меню обеда так же может входить и меню завтрака
dinnerMenu.Add(new MenuItem("Фрукты", "Композиция из яблок, винограда, яблок, киви.", true, 130));
Automatic automatic = new Automatic(allMenus);
automatic.PrintMenu();
Console.ReadKey();
}
}
}
Все меню, Общее меню
--------------------
Меню завтрак, Завтрак
--------------------
Блиный гурман(v), 130
--Блинчики со взбитыми яцами и тостом
Блиный гурман(v), 130
--Блинчики со взбитыми яцами и тостом
Обычны завтра из блинов(v), 130
--Жареный блин с сосиской
Блины с черникой(v), 230
--Блины со свежей черникой
Фруктовые блины(v), 230
--Блины со свежей черникой и клубникой
Меню обеда, Обед
--------------------
Манная каша(v), 120
--Манная каша на миндальном молоке с ванилью
Чечевичный суп(v), 150
--Чечевичный суп с томатами
Суп рассольник(v), 180
--Постный рассольник
Фаршированные перцы(v), 230
--Фаршированные перцы с грибами и кабачком
Овощное рагу, 350
--Овощное рагу с мясом
Свинина, 550
--Свинина под лимонной заправкой
Паста(v), 140
--Спагетти с соусом маринада и ломтик хлеба на закваске
Меню завтрак, Завтрак
--------------------
Блиный гурман(v), 130
--Блинчики со взбитыми яцами и тостом
Блиный гурман(v), 130
--Блинчики со взбитыми яцами и тостом
Обычны завтра из блинов(v), 130
--Жареный блин с сосиской
Блины с черникой(v), 230
--Блины со свежей черникой
Фруктовые блины(v), 230
--Блины со свежей черникой и клубникой
Фрукты(v), 130
--Композиция из яблок, винограда, яблок, киви.

