Паттерн Компоновщик объединяет объекты в древовидные структуры для представления иерархий часть\целое. Компоновщик позволяет клиенту выполнять однородные операции сами отдельными объектами и их совокупностями.
Паттерн Компоновщик позволяет клиенту выполнять однородные операции с комбинациями и отдельными объектами.
Паттерн Компоновщик предоставляет структуру для хранения как отдельных объектов, так и комбинаций.
В реализации паттерна Компоновщик приходится искать баланс между прозрачностью, безопасностью и вашими потребностями.
Рассмотрим пример, в котором нам надо реализовать меню для интерактивного автомата в одной из кафешек.
У нас имеются отдельные классы завтрака и обеда, с набором каких-то блюд. Когда клиент подходит к автомату, он выбирает блюда для завтрака или обеда, но часто бывает такое что в обед могут входить блюда из завтрака. А также дополнятся новыми блюдами сегодняшнего дня. Представляете сложность иерархии построения такой логики программы, когда каждый день придется вносить еще какие-то правки? Вот тут и приходит к нам на помощь Паттерн Компоновщик, который поможет создать древовидное меню блюд, и выводить всю информацию о них.
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
--Композиция из яблок, винограда, яблок, киви.
