2013-10-08 2 views
5

Предположим, я хочу построить список строк (что не является реальным сценарием, но звучит проще объяснить).Должен ли завод иметь конструктор с параметрами?

Я бы интерфейс для моего списка строк завода, который будет выглядеть как этот

public interface IStringsListFactory{ 
    List<string> Create(); 
} 

Но позволяет сказать, один из моих бетонного завода потребуется, чтобы получить этот список строки из файла/базы данных и т.д. ..

public class StringsListFromFile : IStringsListFactory{ 

    private StreamReader _streamReader; 
    public StringsListFromFile(StreamReader sr) //StreamReader is just an example. 
    { 
     _streamReader = sr; 
    } 

    public List<string> Create(){ 
    ///recover the strings using my stream reader... 
    } 
} 

Я знаю, что этот подход будет работать, но мне было интересно, если она нарушает фабричную модель для передачи параметров в конструктор завода, так что я не нарушу интерфейс. Есть ли какие-либо коллеги для этого? Есть ли другое решение, о котором я не думал? Я задаю слишком много вопросов!?! (Да, я знаю ответ на этот вопрос!)

ответ

3

Параметр в конструкторе и сам конструктор должен выполнять только одно и только одно задание: это регистрация зависимостей. Иногда необходимо «вводить» зависимость от фабрики, как описано в абстрактном заводском шаблоне Марка Симана в this answer.

public class ProfileRepositoryFactory : IProfileRepositoryFactory 
{ 
    private readonly IProfileRepository aRepository; 
    private readonly IProfileRepository bRepository; 

    public ProfileRepositoryFactory(IProfileRepository aRepository, 
     IProfileRepository bRepository) 
    { 
     if(aRepository == null) 
     { 
      throw new ArgumentNullException("aRepository"); 
     } 
     if(bRepository == null) 
     { 
      throw new ArgumentNullException("bRepository"); 
     } 

     this.aRepository = aRepository; 
     this.bRepository = bRepository; 
    } 

    public IProfileRepository Create(string profileType) 
    { 
     if(profileType == "A") 
     { 
      return this.aRepository; 
     } 
     if(profileType == "B") 
     { 
      return this.bRepository; 
     } 

     // and so on... 
    } 
} 

Это справедливо в том случае, но не в вашем случае, потому что:

  1. Это делает ваш завод имеет государственные
  2. Это делает ваш завод более гибким, если параметр (поток) впрыскивается в качестве параметра метода

    public class StringsListFromFile : IStringsListFactory{ 
    
        public List<string> Create(StreamReader sr){ 
        ///recover the strings using my stream reader... 
        } 
    } 
    
  3. Если ваш интерфейс должен быть гибким для ввода, используйте общие вместо

  4. дополнительно, то лучше вернуться IEnumerable<string> вместо List<string>
+0

Почему у моей фабрики есть состояние, так как мой член заключен в мой класс? И возвращает IEnumerable проблему производительности? – TopinFrassi

+0

Используя мой проект в точке 2, вы можете создать экземпляр своего класса один раз, а затем использовать другой «StreamReader», не создавая другого объекта того же класса. Это еще одна история, если ваш инъецированный «StreamReader» является своего рода глобальной конфигурацией. Но для этого требуется еще один дизайн. – Fendy

+0

Возвращение 'IEnumerable' - это просто привычка делать« Программу для интерфейса, а не программу для реализации ». Если интерфейс, возвращающий 'IEnumerable', может заставить его также возвращать массив или другую коллекцию, такую ​​как' ObersvableCollection'. – Fendy

0

Вы можете абстрагироваться от реализации того, что его получает. Я также хотел бы лично передать его через в метод вместо конструктора:

public interface IFactoryDataSourceProvider<T> { 
    IList<T> GetData(); 
} 

public class IStringListFactory { 
    public IList<string> Create(IFactoryDataSourceProvider<string> provider) { 
     return _provider.GetData(); 
    } 
} 

Тогда, возможно:

class StreamReaderDataProvider : IFactoryDataSourceProvider<string> { 
    public IList<string> GetData() { 
     using (var streamReader = new StreamReader(...)) { 
      return streamReader.ReadAllLines(); // etc. 
     } 
    } 
} 

var list = factory.Create(new StreamReaderDataSourceProvider()); 

Это все кажется глупо для такого маленького образца .. но я предполагаю, что это не такой маленький, как ваш пример.

+0

В этой ситуации, где бы StreamReader получить аргументы своего конструктора? Я действительно думаю, что DataSourceProvider - хорошая идея, но я не уверен, чтобы в полной мере это понять, может быть, потому, что мой пример слишком мал. – TopinFrassi

+0

Это зависит полностью от вашей текущей настройки. Не зная больше, трудно сказать.Как правило, вы передавали бы его через конструктор, хотя .. где вы его получите заранее, хотя до реализации кода выше. –

0

Factory Pattern заставляет использовать конструктор по умолчанию. Использование параметрического конструктора нарушает идею использования фабричного шаблона, поскольку объект не возвращает действительное состояние классу вызывающего. В вашем случае вы должны инициализировать их после вызова класса фабрики. Это будет дублировать ваш код, и идея использования фабричного шаблона - избежать дублирования кода. Но снова я не знаком со всем сценарием. Но в соответствии с приведенной здесь настройкой вы должны использовать метод вместо Parametric Constructor.

Смежные вопросы