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

本文关键字:参数 构造函数 有一个 工厂 | 更新日期: 2023-09-27 18:34:24

假设我想构建一个字符串列表(这不是真实的场景情况,但听起来更容易解释)。

我会为我的字符串工厂列表提供一个界面,看起来像这样

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

我知道这种方法会奏效,但我想知道它是否破坏了工厂模式以将参数传递给工厂的构造函数,这样我就不会破坏我的接口。这样做有没有对应物?还有我没有想到的另一种解决方案吗?我问的问题太多了吗?!(是的,我知道这个问题的答案!

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

构造

函数中的参数和构造函数本身应该只做一项工作:那就是注册依赖关系。有时,需要将依赖"注入"到工厂,正如 Mark Seeman 在本答案中的抽象工厂模式中所述。

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>

你可以抽象出任何检索它的实现。我也会亲自将其传递到方法而不是构造函数中:

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());

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

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