Фабрика, которая создает одноразовые предметы

#c# #factory #disposable

#c# #завод #расходный материал

Вопрос:

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

 // first solution public class ServiceFactory {  public Reader CreateReader(string configuration)   {  var instance = new DisposableIOResource(configuration);  return new Reader(instance);  } }  // first solution - use case var serviceFactory = new ServiceFactory(); var reader = serviceFactory.CreateReader(configuration) reader.DoSomething(); // NOTE! How do I dispose 'instance'???   // second solution public class ServiceFactory : IDisposable {  private readonly DisposableIOResource _instance;   public ServiceFactory(string configuration)  {  _instance = new DisposableIOResource(configuration);  }   public Reader CreateReader()   {  return new Reader(_instance);  }   public void Dispose()  {  _instance.Dispose();  } }  // second solution - use case using(var serviceFactory = new ServiceFactory(configuration)) {  var reader = serviceFactory.CreateReader():  reader.DoSomething(); }  

— Редактировать В итоге я нашел другое решение, может быть, более чистое:

  public interface IDisposableIOResourceFactory {  DisposableIOResource Create(); }  public class DisposableIOResourceFactory : IDisposableIOResourceFactory {  private readonly string _configuration;  public DisposableIOResourceFactory(string configuration)   {  _configuration = configuration;  }   public DisposableIOResource Create()  {  return new DisposableIOResource(this._configuration);  } }  // third solution  public class ServiceFactory {  public Reader CreateReader(IDisposableIOResourceFactory resourceFactory)   {  return new Reader(resourceFactory);  } }  public class Reader {  public Reader(IDisposableIOResourceFactory resourceFactory) {}   public void DoSomething()  {  using var resource = resourceFactory.Create();  // work on resource  } }  // first solution - use case var serviceFactory = new ServiceFactory(); var resourceFactory = new DisposableIOResourceFactory(); var reader = serviceFactory.CreateReader(resourceFactory); reader.DoSomething();   

Комментарии:

1. Мне кажется, что класс Reader должен реализовать IDisposable. Чего вы пытаетесь достичь?

2. Оба технически являются фабриками, но ваша вторая реализация использует шаблон одноэлементного кода, который обычно не совпадает с фабрикой. Я бы сосредоточился не столько на ярлыках, сколько на том, что код делает для вас, и на проблемах, которые он решает.

3. using var reader = serviceFactory.CreateReader(configuration); а затем Reader отвечает за утилизацию любых своих внутренних ресурсов.

4. У фабрики нет возможности угадать, когда потребитель закончит использовать объект. Следовательно, это должен быть класс Reader, реализующий IDisposable.

5. @Zoidbergseasharp Позволил мне глубоко погрузиться в мой вопрос. Просто подумайте о «Читателе» как о адаптере на одноразовом ресурсе, который помогает вам читать на этом ресурсе. Теперь конечный пользователь фабрики не знает, как создать этот ресурс, поэтому вы не можете просто попросить его создать одноразовый ресурс. В этом случае единственный, кто знает, как его создать, — это фабрика, но в этом случае «как вы распоряжаетесь этим объектом»?

Ответ №1:

Ваша фабрика-это не то, что нужно для реализации IDisposable. Ваш Читатель знает.

Все в порядке.

 // first solution public class ServiceFactory {  public Reader CreateReader(string configuration)   {  var instance = new DisposableIOResource(configuration);  return new Reader(instance);  } }  

Вы не включаете класс Reader

Но он должен реализовать IDisposable

 public class Reader : IDisposable {  private readonly DisposableIOResource _instance;   // Code Here  public Reader(DisposableIOResource instance) {  _instance = instance;  }   public void Dispose() {  _instance?.Dispose();  } }   

Затем, когда вы создаете его, вы помещаете его в использование

 var serviceFactory = new ServiceFactory(configuration);  using(var reader = serviceFactory.CreateReader()) {  reader.DoSomething(); }   

Комментарии:

1. Это только половина истории, Reader нужно разобраться instance . Кроме того, я рекомендую использовать обновленный using синтаксис, который существует с C# 8

2. Я намеренно опустил Reader удаление instance , потому что этот код не был включен в исходный вопрос. Но да, это верно. Согласился, если возможно, использовать более свежий синтаксис, но из вопроса было неясно, какую языковую версию он использовал, поэтому я выбрал наиболее совместимую.

3. @DavidG Это не вопрос о том, как реализовать IDisposable — таких уже миллиард. Каддюк ответил на основной вопрос. Если ОП хочет узнать о реализации, он может искать и найдет.

4. @Ricibob Я хорошо знаю об этом, но OP специально спросил, как избавиться от внутреннего объекта, а не от Reader объекта.

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