Форум программистов, компьютерный форум, киберфорум
C# .NET
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 5.00/6: Рейтинг темы: голосов - 6, средняя оценка - 5.00
0 / 0 / 0
Регистрация: 28.02.2014
Сообщений: 23

Когда следует использовать декораторы?

24.08.2024, 13:45. Показов 1509. Ответов 20

Студворк — интернет-сервис помощи студентам
Когда следует использовать декораторы?
Когда надо динамически добавлять к объекту новые функциональные возможности. При этом данные возможности могут быть сняты с объекта.
ВОПРОС . А как их можно снять ? например такой пример.

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
class Program
{
    static void Main(string[] args)
    {
       
 
        Pizza pizza3 = new BulgerianPizza();
        pizza3 = new TomatoPizza(pizza3);
        pizza3 = new CheesePizza(pizza3);// болгарская пиццы с томатами и сыром
        Console.WriteLine("Название: {0}", pizza3.Name);
        Console.WriteLine("Цена: {0}", pizza3.GetCost());
 
        Console.ReadLine();
    }
}
 
abstract class Pizza
{
    public Pizza(string n)
    {
        this.Name = n;
    }
    public string Name {get; protected set;}
    public abstract int GetCost();
}
 
class ItalianPizza : Pizza
{
    public ItalianPizza() : base("Итальянская пицца")
    { }
    public override int GetCost()
    {
        return 10;
    }
}
class BulgerianPizza : Pizza
{
    public BulgerianPizza()
        : base("Болгарская пицца")
    { }
    public override int GetCost()
    {
        return 8;
    }
}
 
abstract class PizzaDecorator : Pizza
{
    protected Pizza pizza;
    public PizzaDecorator(string n, Pizza pizza) : base(n)
    {
        this.pizza = pizza;
    }
}
 
class TomatoPizza : PizzaDecorator
{
    public TomatoPizza(Pizza p) 
        : base(p.Name + ", с томатами", p)
    { }
 
    public override int GetCost()
    {
        return pizza.GetCost() + 3;
    }
}
 
class CheesePizza : PizzaDecorator
{
    public CheesePizza(Pizza p)
        : base(p.Name + ", с сыром", p)
    { }
 
    public override int GetCost()
    {
        return pizza.GetCost() + 5;
    }
}
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
24.08.2024, 13:45
Ответы с готовыми решениями:

Когда следует использовать значимый тип, а когда ссылочный?
Почитал про значимые и ссылочные типы, ознакомился с отличиями между ними, как работают те и другие. Но хотел бы увидеть от...

Когда нужно использовать структуры, когда классы, а когда словарь?
Хеллоу. Не могу понять, когда, что, нужно использовать. Допустим мне нужно получить объект, который имеет список объектов. И...

Когда нужно использовать абстрактный класс а когда интерфейс
Я вроде бы и понимаю эту тему, но не до конца. Абстракция нужна для определения подтипов сущностей, для их классификации, а интерфейс для...

20
 Аватар для IamRain
4693 / 2701 / 734
Регистрация: 02.08.2011
Сообщений: 7,226
24.08.2024, 14:01
Цитата Сообщение от ivi_ivi Посмотреть сообщение
А как их можно снять ? например такой пример.
Если объект занимался логированием, то можно это логирование теперь убрать. А добавлять только в декораторе.
То есть снимается фактически редактированием кода объекта.
0
0 / 0 / 0
Регистрация: 28.02.2014
Сообщений: 23
24.08.2024, 14:18  [ТС]
А можно пример если не трудно. Я просто не могу не где найти информацию на эту тему.
0
 Аватар для IamRain
4693 / 2701 / 734
Регистрация: 02.08.2011
Сообщений: 7,226
24.08.2024, 14:27
ivi_ivi, как по мне у вас не самый удачный пример - декораторы добавляют новую обязанность - а новая цена - это свойство объекта.
Фактически у вас другой тип объекта - пицца с томатами, которая очевидно дороже базовой.
На деле же никаких обязанностей этот декоратор не добавляет.

Добавлено через 5 минут
Цитата Сообщение от ivi_ivi Посмотреть сообщение
если не трудно.
- вот тут есть пример.

Добавлено через 1 минуту
Сущность - PostService, декоратор - добавляет диагностическую информацию о получении поста (время запроса).
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16115 / 11236 / 2887
Регистрация: 21.04.2018
Сообщений: 33,037
Записей в блоге: 2
24.08.2024, 14:27
ivi_ivi, дополню IamRain.
Мне кажется здесь для примера подойдёт декоратор "Пицца в упаковке".
Разные пиццы в разных упаковках, а объединяет их декоратор.
При этом можно "вынуть из упаковки" и будет опять просто пицца.
0
 Аватар для IamRain
4693 / 2701 / 734
Регистрация: 02.08.2011
Сообщений: 7,226
24.08.2024, 14:30
Или те же репозитории - базовая версия ходит в базу, декоратор - добавлят кэш.

Добавлено через 2 минуты
Раз уж за декоратор взялись, попробуйте поискать отличия от Proxy-паттерна.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16115 / 11236 / 2887
Регистрация: 21.04.2018
Сообщений: 33,037
Записей в блоге: 2
24.08.2024, 14:44
Цитата Сообщение от IamRain Посмотреть сообщение
попробуйте поискать отличия от Proxy-паттерна.
Расширю список: Декоратор (Wrapper), Proxy, Adapter, Facade.
Их часто путают между собой.
0
 Аватар для IamRain
4693 / 2701 / 734
Регистрация: 02.08.2011
Сообщений: 7,226
24.08.2024, 14:56
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Facade.
Ну вот это я бы не стал сюда кидать, Фасад - это когда достаточно много (обычно) под капотом, и нужен удобный доступ к API этого добра, необязательно скрывая само добро.
Цепляясь за слова - капот автомобиля, это своего рода фасад.

Добавлено через 1 минуту
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Adapter
В точку.

Добавлено через 2 минуты
UoW паттерн - транзакционный фасад над репозиториями, по сути.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16115 / 11236 / 2887
Регистрация: 21.04.2018
Сообщений: 33,037
Записей в блоге: 2
24.08.2024, 16:35
Цитата Сообщение от IamRain Посмотреть сообщение
Фасад - это когда достаточно много (обычно) под капотом, и нужен удобный доступ к API этого добра, необязательно скрывая само добро
Самый частый пример Фасад в моей практике - это ViewModel из MVVM. По сути это Фасад для Модели.
Но в простых случаях, при малом количестве функционала, может превратиться и в Proxy.

C#
1
2
3
4
5
6
7
public partial class Point2D : INotifyPropertyChanged
{
    private Point point;
 
    public double X {get => point.X; set => {point.X = value; ....}}
    public double Y {get => point.Y; set => {point.Y = value; ....}}
}
0
 Аватар для IamRain
4693 / 2701 / 734
Регистрация: 02.08.2011
Сообщений: 7,226
24.08.2024, 16:42
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Самый частый пример Фасад в моей практике - это ViewModel из MVVM.
Ну не, фасад - это явно нечто большее чем просто композиция над одним объектом. Конкретно в вашем примере это просто Wrapper (пустой Decorator, типа того).
В GoF хорошее определение дается, насколько я помню. Вспомните тот же UoW.
Дискутировать не хочу.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16115 / 11236 / 2887
Регистрация: 21.04.2018
Сообщений: 33,037
Записей в блоге: 2
24.08.2024, 16:53
Цитата Сообщение от IamRain Посмотреть сообщение
Ну не, фасад - это явно нечто большее чем просто композиция над одним объектом. Конкретно в вашем примере это просто Wrapper (пустой Decorator, типа того).
Я не для дискуссии что как правильно называть.
Я к тому, что все эти паттерны на практике могут "перетекать" друг в друга.
Есть некие идеальные, абсолютные варианты. Но между ними есть масса промежуточных, когда непонятно к какому собственно паттерну стоит относить эту реализацию.

Добавлено через 1 минуту
Поэтому следует изучить их все, понимать как их реализовывать, понимать какая разница между ними, но и понимать, что на практике скорее всего придётся делать нечто совмещающее идеи нескольких паттернов.
0
 Аватар для IamRain
4693 / 2701 / 734
Регистрация: 02.08.2011
Сообщений: 7,226
24.08.2024, 17:11
Лучший ответ Сообщение было отмечено ivi_ivi как решение

Решение

Цитата Сообщение от Элд Хасп Посмотреть сообщение
Но между ними есть масса промежуточных, когда непонятно к какому собственно паттерну стоит относить эту реализацию.
Согласен, но мы сейчас обсуждаем ООП-паттерны, которые позаимствовали свои наименования из других отраслей реальной жизни (строительства и архитектуры - те же фасад, мост, декоратор). Соответственно, если говорим про фасад зданий (оригинальное применение этого термина), то здание - это некая сложная подсистема, в котором есть множество этажей, подразделений рабочих и прочего добра для обеспечения деятельности. Однако если прохожий с улицы пройдет мимо и прочитает на фасаде табличку, то сразу поймет, где он оказался, скажем, перед входом в управление госнаркоконтроля по такому-то району такого-то города.
Короче, в смысловом понимании должно быть нечто большее, чем просто вагончик с шаурмой - несколько подсистем (в оригинале вроде такое именование было в GoF).
Во всяком случае, я склоняюсь именно к такому определению.
2
0 / 0 / 0
Регистрация: 28.02.2014
Сообщений: 23
25.08.2024, 17:47  [ТС]
Добрый день . Но тут кеширование а не снятие обертки декоратора. Я читал что объект создается потом оборачивается N числом дкораторов . Каждый на каждый новый объект создаваемого декоратора выделяется место в памяти и оно там хранится . Вообщем получается один объект оборачивается в другой и можно отменить эту обертку и вернуться к первому состоянию. В моем примере сначала объект будет типа ItalianPizza после обертки тип его изменится на TomatoPizza и после последней обертки тип объекта станет типа CheesePizza. Так вот все созданные объекты хранятся в памяти и можно переходить от например типа обертки CheesePizza к типу ItalianPizz. То есть отменить декорирование объекта и прийти к его начальному состоянию.
Может я где то ошибаюсь и не правильно понял.
0
0 / 0 / 0
Регистрация: 28.02.2014
Сообщений: 23
26.08.2024, 22:55  [ТС]
Хотелось бы до конца рассмотреть этот паттерн но почему то теоретики которые пишут паттерны не рассматривают этот случай.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16115 / 11236 / 2887
Регистрация: 21.04.2018
Сообщений: 33,037
Записей в блоге: 2
27.08.2024, 01:20
Цитата Сообщение от ivi_ivi Посмотреть сообщение
Хотелось бы до конца рассмотреть этот паттерн но почему то теоретики которые пишут паттерны не рассматривают этот случай.
Декоратор (Decorator) | Паттерны в C# и .NET | METANIT.COM

Там пример как раз про пиццу.
0
0 / 0 / 0
Регистрация: 28.02.2014
Сообщений: 23
27.08.2024, 11:59  [ТС]
Привет . Я свой пример и брал отсюда но к сожалению тут только упаковка.
0
 Аватар для IamRain
4693 / 2701 / 734
Регистрация: 02.08.2011
Сообщений: 7,226
27.08.2024, 14:39
Цитата Сообщение от ivi_ivi Посмотреть сообщение
Хотелось бы до конца рассмотреть этот паттерн
Тут нечего рассматривать, добавление дополнительной обязанности - основное предназначение паттерна. Метанит не изобилует эталоннными примерами.
Читайте GoF и оттуда же примеры смотрите.
0
HF
 Аватар для HF
1303 / 882 / 199
Регистрация: 09.09.2011
Сообщений: 2,590
Записей в блоге: 2
27.08.2024, 15:44
Походу тут проблема вообще не в декораторе, а в голове.

Цитата Сообщение от ivi_ivi Посмотреть сообщение
ВОПРОС . А как их можно снять ?
А у меня тоже вопрос - Зачем? Что нужно добиться или что у вас за требование? Что нужно получить из запакованной пицы?
Во всей теме ответа не видел.

Цитата Сообщение от ivi_ivi Посмотреть сообщение
Я читал что объект создается потом оборачивается N числом дкораторов . Каждый на каждый новый объект создаваемого декоратора выделяется место в памяти и оно там хранится .
После прочитанного лучше немного самому подумать, чтобы не буквы запомнились, а смысл.
Да, если оборачивать объекты в объекты в объекты... то их будет много и они будут "живые", а ресурсы выделяться на хранение.
Если цели не стоит, то делают оптимизацию. Например, если не нужно "разворачивать" пиццу, то я бы брал только Name и по сути менялось бы только название и цена. Но это просто пример.

Цитата Сообщение от ivi_ivi Посмотреть сообщение
Так вот все созданные объекты хранятся в памяти и можно переходить от например типа обертки CheesePizza к типу ItalianPizz. То есть отменить декорирование объекта и прийти к его начальному состоянию.
Ну дак и переходите. Очевидно "знания" о базовой пицце хранит protected Pizza pizza. Вот и "разворачивайте" цепочку в обратную сторону.
- использовать внутренний метод для доступа к protected свойству
- или сделать public для этого свойства
Ну это всё некрасиво может быть. Только ради примера.

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
void Main()
{
    Pizza pizza2 = new ItalianPizza();
 
    pizza2 = new TomatoPizza(pizza2);// итальянская пиццы с помидорами
    pizza2 = new CheesePizza(pizza2);// итальянская пиццы с сыром
    pizza2 = new TomatoPizza(pizza2);// итальянская пиццы с помидорами
    pizza2 = new CheesePizza(pizza2);// итальянская пиццы с сыром
    Console.WriteLine("Название: {0}", pizza2.Name);
    Console.WriteLine("Цена: {0}", pizza2.GetCost());
 
    pizza2.Dump();
 
    pizza2.GetBase().Dump();
    pizza2.GetBase().GetBase().Dump();
    pizza2.GetBase().GetBase().GetBase().Dump();
    pizza2.GetBase().GetBase().GetBase().GetBase().Dump();
}
 
abstract class Pizza
{
    public Pizza(string n)
    {
        this.Name = n;
    }
    public string Name { get; protected set; }
    public abstract int GetCost();
    public abstract Pizza GetBase();
}
 
class ItalianPizza : Pizza
{
    public ItalianPizza() : base("Итальянская пицца")
    { }
    public override int GetCost()
    {
        return 10;
    }
    public override Pizza GetBase()
    {
        return this;
    }
}
class BulgerianPizza : Pizza
{
    public BulgerianPizza()
        : base("Болгарская пицца")
    { }
    public override int GetCost()
    {
        return 8;
    }
    public override Pizza GetBase()
    {
        return this;
    }
}
 
abstract class PizzaDecorator : Pizza
{
    protected Pizza pizza;
    public PizzaDecorator(string n, Pizza pizza) : base(n)
    {
        this.pizza = pizza;
    }
    public override Pizza GetBase()
    {
        return pizza;
    }
}
 
class TomatoPizza : PizzaDecorator
{
    public TomatoPizza(Pizza p)
        : base(p.Name + ", с томатами", p)
    { }
 
    public override int GetCost()
    {
        return pizza.GetCost() + 3;
    }
}
 
class CheesePizza : PizzaDecorator
{
    public CheesePizza(Pizza p)
        : base(p.Name + ", с сыром", p)
    { }
 
    public override int GetCost()
    {
        return pizza.GetCost() + 5;
    }
}
 
// Итальянская пицца, с томатами, с сыром, с томатами
// Итальянская пицца, с томатами, с сыром
// Итальянская пицца, с томатами
// Итальянская пицца
И вот, разворачивайте пока не закончатся помидоры наследования.

Цитата Сообщение от ivi_ivi Посмотреть сообщение
Может я где то ошибаюсь и не правильно понял.
Вам дали инструмент. Теперь нужно применить мозг и найти решение. Готовых решений нет.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16115 / 11236 / 2887
Регистрация: 21.04.2018
Сообщений: 33,037
Записей в блоге: 2
28.08.2024, 00:25
Лучший ответ Сообщение было отмечено ivi_ivi как решение

Решение

Цитата Сообщение от ivi_ivi Посмотреть сообщение
Я свой пример и брал отсюда но к сожалению тут только упаковка.
К сожалению прямо сейчас у меня МЕТАНИТ не доступен, поэтому без цитаты, а по смыслу
Основной вывод оттуда: патер позволяет вместо 9 разных классов, ввести 3 новых классов-декораторов.

Поймите, цель паттернов - это не "теоретические выдумки сферических профессоров в вакууме", а упрощение программирования (в первую очередь - коллективного).
Если применение паттерна усложняет реализацию, то либо вы не правильно реализовали паттерн, либо выбрали не тот паттерн, либо , вообще, не нужен здесь ни один из типовых паттернов.

Конечно. это не относится к периоду обучения, когда искусственно переусложняют реализацию с цель получения опыта.
1
1167 / 885 / 517
Регистрация: 09.04.2014
Сообщений: 2,095
29.08.2024, 12:26
Цитата Сообщение от ivi_ivi Посмотреть сообщение
но к сожалению тут только упаковка.
Декоратор имеет альтернативное название — обёртка. Оно более точно описывает суть паттерна: вы помещаете целевой объект в другой объект-обёртку, который запускает базовое поведение объекта, а затем добавляет к результату что-то своё.
https://refactoring.guru/ru/de... /decorator
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
29.08.2024, 12:26
Помогаю со студенческими работами здесь

Когда нужно использовать ссылку с out, а когда с ref
Не давно начал учить С# но не могу понять когда надо использовать оut или ref , я так понимаю что это ссылки как в С++. Единственно в чем...

Когда использовать ссылочные типы, а когда использовать типы значений?
Как это определить?

Когда использовать IEquatable<T>, а когда IStructuralEquatable?
Когда использовать IEquatable&lt;T&gt;, а когда IStructuralEquatable?

Когда использовать отношение, а когда ключи?
Подскажите правильно ли понимаю, чтобы получать родительские дочерние строки не обязательно создавать PK, FK достаточно создать отношение:...

Какой вид разделителя в именах каталогов следует использовать в директиве #include и почему?
1. Какой вид разделителя в именах каталогов следует использовать в директиве #include и почему?


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Access
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru