Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should a factory have a constructor with parameters?

Let's say I want to build a list of strings (Which is not the real scenario case, but sounds simpler to explain).

I'd have an interface for my list of strings factory that would look like this

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

But lets say one of my concrete factory would require to get this list of string from a file/database etc..

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... 
   }
}

I know this approach would work, but I was wondering if it breaks the Factory Pattern to pass parameters to the factory's constructor so I wouldn't break my interface. Are there any counterparts to doing this? Is there another solution I didn't think of? Am I asking too many questions!?! (Yeah, I know the answer to this one!)

like image 563
IEatBagels Avatar asked Oct 08 '13 02:10

IEatBagels


1 Answers

Parameter in constructor, and constructor itself, should only do one and only one job to do: that is registering dependency. Sometimes, it is needed to "inject" the dependency to factory, as described at abstract factory pattern by Mark Seeman in 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...
    }
}

It is valid in that case, but not in your case because:

  1. It makes your factory have state
  2. It makes your factory more flexible if the parameter (stream) injected as method parameter

    public class StringsListFromFile : IStringsListFactory{
    
       public List<string> Create(StreamReader sr){ 
         ///recover the strings using my stream reader... 
       }
    }
    
  3. If your interface should be flexible for the input, use generic instead

  4. additionally, it is better to return IEnumerable<string> instead of List<string>
like image 140
Fendy Avatar answered Oct 19 '22 22:10

Fendy