Начинать

Для начала сделаем такое отступление, хочу начать цикл статей о шаблонах проектирования. Я думаю, что все хотят, чтобы их код был легко масштабируемым, верно. Все паттерны разделены на категории, и перед их рассмотрением лучше начать изучение с самих паттернов, иначе вы не поймете, почему Декоратор — составной паттерн, а Фабрика — генеративный паттерн. После изучения уже будет интуитивно понятно, почему тот или иной узор относится к той или иной категории.

Для изучения самих паттернов я постараюсь не углубляться в определения, а показать примеры, поставить задачу и решить задачу с помощью паттерна. Мы возьмем компанию «Сесла Моторс» и решим поставленные перед ней задачи. Не позволяйте имени заставить вас чувствовать, что вы где-то о нем слышали. Это не правильно. Ведь компания занимается только производством электромобилей. И такое редко встретишь в реальном мире. Это должно быть интересно. Пойдем!.

Пятно

Наша компания предлагает различные модели автомобилей. Основными из них являются «Модель А» и «Модель Б». Сами автомобили находятся в разных ценовых сегментах. Но есть опции, которые можно добавить в конфигурацию обеих машин. А компания «Цесла Моторс» хочет без труда получить окончательную цену и информацию о собранной комплектации электромобиля. Как они могут это сделать?

попробуем решить

Начнем с того, что паттерн декоратор на самом деле является удобной «оберткой» для основного класса, каждая обертка придает основному классу новые свойства. Чтобы иметь возможность «обернуть» основной класс, у вас должен быть базовый класс как для оболочки, так и для основного класса. Является ли это абстрактным классом Машина.

public abstract class Car
{
    private string Description;

    public Car()
    {
        Description = "Unknown car";
    }

    public Car(string description)
    {
        Description = description;
    }

    public virtual string GetDescription()
    {
        return Description;
    } 

    public abstract decimal Price();
}

Обратите внимание, что свойства Цена И Описание иметь разные учетные данные для доступа. Этим я хотел показать гибкость этой модели, поэтому не имеет значения, используем ли мы абстрактный Или виртуальный. Главное уметь заменить имущество.

ЧИТАТЬ   РЖД достроит магистральную квантовую сеть до Казани и Ростова-на-Дону

От Машина классы будут наследоваться Модель А И МодельB. Напишем их реализацию. Пока все хорошо и тривиально

public class ModelA : Car
{
    public ModelA() : base("Default ModelA") { }

    public ModelA(string description) : base(description) { }

    public override decimal Price()
    {
        return 40_000.034m;
    }
}

Вы можете сами написать реализацию ModelB.

По моему я про упаковку другое сказал. Хм… Тут мне кажется запустится основная логика декоратора. Давайте подумаем, как обернуть экземпляры класса Модель А Или МодельB новая возможность. Я бы написал дополнительный абстрактный класс, который содержал бы логику оболочки

public abstract class CarPartsDecorator : Car
{
    public Car _car;

    public CarPartsDecorator(Car car)
    {
        _car = car;
    }
}

В будущем в этом классе можно будет написать абстрактный метод для реализации в подклассах. То есть добавить дополнительные свойства для опций автомобиля.

Теперь реализуем один из вариантов Автоматическая система парковки (детский класс АвтомобильЧастиДекоратор)

public class AutomaticParkingSystem : CarPartsDecorator
{
    private readonly decimal _ownPrice;
    private readonly string _description;

    public AutomaticParkingSystem(Car car,
        string description, decimal ownPrice = 1_500m) : base(car)
    {
        _ownPrice = ownPrice;
        _description = description;
    }

    public override decimal Price()
    {
        return _car.Price() + _ownPrice;
    }

    public override string GetDescription()
    {
        return _car.GetDescription() + _description;
    }
}

Вы также можете сами написать другие классы опционов.

Любой класс! Теперь давайте посмотрим, как выглядит наш сервис в итоге.

Car car = new ModelA();

car = new WheelDisk(car, ownPrice: 2_300.4m);
car = new AutomaticParkingSystem(car, description: ", new automatic parking system");

Console.WriteLine($"ModelA price: {car.Price()}");
Console.WriteLine($"ModelB price: {car.GetDescription()}");

На выходе получилось так:

ModelA price: 43800,434
ModelB price: Default ModelA, simple wheel disk, new automatic parking system

Source

От admin