.Net developer, data scientist
Рад приветствовать вас на моём канале. Сегодня мы рассмотрим очередной шаблон проектирования и во время детального анализа сценария, когда данный шаблон должен использоваться, я сделаю подводку к следующему принципу SOLID. Шаблон, о котором сегодня пойдет речь, называет «Декоратор», а принцип SOLID, который активно эксплуатирует данный шаблон, называется принцип открытости / закрытости или на английском языке Open / Close principle, что соответствует букве O в аббревиатуре SOLID. Итак, в сегодняшнем видео – шаблон «Декоратор», в следующем видео через неделю «Принцип открытости / закрытости».
Как всегда, начнем со сценария использования. Сценарий следующий – у вас есть класс с определенной функциональностью, и вы должны изменить эту функциональность. Однако этот класс используют другие компоненты и изменения, которые вы планируете сделать, могли бы потенциально навредить эти компонентом.
Чтобы было более понятно воспользуемся примером, который мы использовали в шаблоне проектирования «Стратегия» и при объяснении принципа единственной ответственности. Там был класс «Калькулятор» с 4 арифметическими действиями и нам надо было изменить действие умножения путем увеличения вдвое результата умножения. Так вот представим себе, что классом «Калькулятор» пользуются несколько компонентов нашего приложения, а только в одном компоненте необходима функциональность удвоения результат умножения.
Какие возможности у нас есть:
Какую возможность мы будем использовать:
Что необходимо знать о шаблоне декоратор:
Сложно описывать шаблон декоратор без примера в коде. Поэтому давайте рассмотрим пример. Сегодня это будет приложение, в котором мы рассчитываем стоимость доставки заказа и сумму комиссии за оплату заказа. Стоимость доставки зависит от выбранной компании поставщика, а комиссия зависит от суммы оплаты. Запускаем Visual Studio…
Пример посылок был примером выдуманным. Целью данного примера было только лишь показать, как можно использовать шаблон «Декоратор». Я хотел бы поделиться с вами еще одним примером, когда я на практике использовал шаблон проектирования «Декоратор». Есть некоторый класс, который может выполнить любой запрос на базе данных. Функциональность класса была заточена под выполнение команды «UPDATE». Проблема заключалась в том, что если во время выполнения нескольких команд «UPDATE» появлялась ошибка, то часть данных была изменена, а часть команд после возникновения ошибки не была выполнена и, соответственно, часть данных не была изменена. Для того чтобы решить эту задачу, не изменяя исходного класса, я создал декоратор, который добавлял обслуживание транзакций для запроса, которые выполнялись в декорируемом классе. В коде это выглядело следующим образом.
public class UpdateQueryRunner : IQueryRunner
{
public int RunQuery(string queryString)
{
string connectionString = GetConnectionString()
using (SqlConnection connection = new SqlConnection(connectionString))
{
SqlCommand command = new SqlCommand(queryString, connection);
try
{
connection.Open();
return command.ExecuteNonQuery();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return 0;
}
}
}
}
public class TransactionUpdateQueryRunner : IQueryRunner
{
private readonly IQueryRunner _decoratedQueryRunner;
public TransactionUpdateQueryRunner(IQueryRunner queryRunner)
{
_decoratedQueryRunner = queryRunner;
}
public int RunQuery(string queryString)
{
var transactionQuery = $"BEGIN TRAN; {queryString} COMMIT TRAN;"
return _decoratedQueryRunner.RunQuery();
}
}
public interface IQueryRunner
{
int RunQuery(string queryString);
}
//пример использования кода, указанного выше.
var updateQueryRunner = new UpdateQueryRunner();
var transactionQueryRunner = new TransactionUpdateQueryRunner(updateQueryRunner);
transactionQueryRunner.RunQuery("UPDATE [TABLE] SET Name='ABC' WHERE ID=1;") //конечный запрос BEGIN TRAN; UPDATE [TABLE] SET Name='ABC' WHERE ID=1; COMMIT TRAN;
Пример кода из видео на GitHub
Для открытия файла проекта необходимо Visual Studio 2019.