工厂应该有一个带参数的构造函数吗?

时间:2013-10-08 02:53:46

标签: c# design-patterns factory-pattern

假设我想构建一个字符串列表(这不是真实的情况,但听起来更简单)。

我的字符串工厂列表的界面看起来像这样

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 个答案:

答案 0 :(得分:3)

构造函数中的参数和构造函数本身应该只执行一个且只能执行一个作业:即注册依赖项。有时,需要将依赖关系“注入”到工厂,正如Mark Seeman在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>

答案 1 :(得分: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());

对于如此小的样本来说,这一切似乎都很愚蠢..但我认为这并不像你的例子那么小。

答案 2 :(得分:0)

Factory Pattern强制您使用Default Constructor。 使用参数构造函数违反了使用工厂模式的想法,因为对象不会将有效状态返回给调用者类。在您的情况下,您必须在工厂类调用后初始化它们。这将复制您的代码,使用工厂模式的想法是避免代码重复。 但我又不熟悉整个场景。但是根据您在此处显示的设置,您应该使用一种方法代替Parametric Constructor。