TGViewer
.NET Разработчик .NET Разработчик @netdeveloperdiary · 6.75K subscribers
Post #2549 2.68K
День 2107. #ЗаметкиНаПолях
Не Внедряйте Сторонние Зависимости. Используйте Декораторы. Продолжение

Начало

Устойчивый декоратор
Задача в этом примере - сделать зависимость IService более устойчивой. Класс MyApi станет более устойчивым транзитивно, получив более устойчивую зависимость. Поэтому первым шагом рефакторинга является введение устойчивого декоратора:
public class ResilientService(
ResiliencePipeline pipeline,
IService inner) : IService
{
public QueryResult RetrieveMultiple(
QueryByAttribute query)
{
return pipeline.Execute(()
=> inner.RetrieveMultiple(query));
}
}

Как и все декораторы, этот класс содержит экземпляр IService, а также сам реализует этот интерфейс. Вместо внедрения ResiliencePipelineProvider<string> только для вызова GetPipeline для него, он просто получает ResiliencePipeline и сохраняет объект для использования в методе RetrieveMultiple. Обратите внимание, что тут используется первичный конструктор.

Упрощение MyApi
Теперь, нам не нужен код Polly в MyApi:
public class MyApi
{
private IService _svc;

public MyApi(IService svc)
{
_svc = svc;
}

public List<string> GetSomething(
QueryByAttribute query)
{
var result = svc.RetrieveMultiple(query);
return result.Entities
.Cast<string>().ToList();
}
}

Да, в MyApi почти ничего не осталось, но напомню, что у нас упрощённый пример, и GetSomething может быть гораздо длиннее и требовать тестирования. А в нынешнем виде тестирование тривиально:
[Theory]
[InlineData("foo", "bar", "baz")]
public void GetSomething(params string[] expected)
{
var svc = new Mock<IService>();
svc
.Setup(s => s.RetrieveMultiple(
new QueryByAttribute()))
.Returns(new QueryResult(expected));

var sut = new MyApi(svc.Object);

var actual = sut.GetSomething(
new QueryByAttribute());

Assert.Equal(expected, actual);
}

Однако важнее то, что теперь нам не только удалось исключить сторонние зависимости из кода приложения, но и упростить его. Создать устойчивый объект MyApi можно в корне композиции:
var svc = new ResilientService(pipeline, inner);
var myApi = new MyApi(svc);

Так мы отделяем код приложения от сторонних зависимостей. Мы определяем ResilientService в корне композиции и оставляем зависимость от Polly там.

Окончание следует…

Источник:
https://blog.ploeh.dk/2024/09/02/keeping-cross-cutting-concerns-out-of-application-code/
  • 👍 12
More from @netdeveloperdiary
  1. Oct 6, 2026🦈 Открытое собеседование на Middle C# | 6 октября, 19:00 МСК Приглашаем на открытое собес…
  2. Oct 6, 2026День 2806. #ЗаметкиНаПолях Типы Коллекций в .NET, Которые Стоит Попробовать. Начало Больши…
  3. Oct 5, 2026День 2805. #ЧтоНовенького #NET11 Аргументы в Выражениях Коллекций в C#15 В C#15 реализован…
  4. Oct 4, 2026День 2804. #ВопросыНаСобеседовании Марк Прайс предложил свой набор из 60 вопросов (как тех…
  5. Oct 3, 2026Post #3360
  6. Oct 3, 2026День 2803. #Оффтоп Чем Заняться, Пока Работают Агенты? У VS Code Есть Ответ Сейчас большую…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →