将工厂注入 A Class

Injecting A Factory Into A Class

我正在开发用于生成某种字符串的应用程序功能。我有一个界面:

interface IStringGenerator
{
    string GenerateNext();
}

现在我已经在 class 中实现了这个接口,它有一个构造函数和一个参数:

class FixedLengthStringGenerator : IStringGenerator
{
    // The class needs some dependencies, but I ignored them here to keep it simple
    public FixedLengthStringGenerator(int length /*and dependencies*/)
    { . . . }

    public string GenerateNext()
    { . . . }

    .
    .
    .
}

此实现仅生成固定给定长度的所需字符串 lengthGenerateNext() 每次调用 returns 一个想要的字符串,直到没有剩余然后它 returns null。考虑到这些,我需要 IStringGenerator 的另一个实现,它可以生成长度介于最小值和最大值之间的字符串。我认为有这样的东西是很自然的:

class MinMaxLengthStringGenerator : IStringGenerator
{
    int _MinLength;
    int _MaxLength;
    int _Length;
    IStringGenerator _StringGenerator;

    public MinMaxLengthStringGenerator(int minLength, int maxLength)
    {
        _MinLength = minLength;
        _MaxLength = maxLength;

        _Length = minLength;
        _StringGenerator = new FixedLengthStringGenerator(_Length);
    }

    public string GenerateNext()
    {
        if(_Length > _MaxLength)
            return null;

        string generatedString = _StringGenerator.GenerateNext();

        if(generatedString == null)
        {
            _Length++;
            if(_Length <= _MaxLength)
            {
                _StringGenerator = new FixedLengthStringGenerator(_Length);
                return _StringGenerator.GenerateNext();
            }
            else
                return null;
        }
        else
            return generatedString;
    }
}

但是直接创建实例并不是一个好主意。相反,我可以使用工厂来获取 FixedLengthStringGenerator 的实例。但我仍然认为这不是一个好的做法,因为它取决于 FixedLengthStringGenerator。而且如果我以后想用别的替代方案class,这样就无法从外面接收了

我的问题是将工厂注入我的 MinMaxLengthStringGenerator 是否正确(从模式的角度来看)?

更准确地说,考虑

interface IFixedLengthStringGeneratorFactory
{
    FixedLengthStringGenerator Create(int length);
}

我应该像下面这样声明 MinMaxLengthStringGenerator 的构造函数吗?

public MinMaxLengthStringGenerator(int minLength, int maxLength, IFixedLengthStringGeneratorFactory factory)
{ . . . }

我认为你非常接近。考虑一个实现这个接口的工厂:

interface IStringGeneratorFactory
{
    IStringGenerator CreateFixedLengthStringGenerator(int length);

    IStringGenerator CreateMinMaxLengthStringGenerator(int minLength, int maxLength, IStringGeneratorFactory factory);

    /* other types? */
}

你在 MinMaxLengthStringGenerator 内分配给 _StringGenerator 然后变成这样:

_StringGenerator = _stringGeneratorFactory.CreateFixedLengthStringGenerator(_Length);

这会从 MinMaxLengthStringGenerator 中删除对 FixedLengthStringGenerator 的具体实现的引用。

希望对您有所帮助!

已更新 那么设计就是这样。

尽管应该尽可能避免在构造函数中注入参数。 现在,我们可以通过任何标准 DI 容器注入依赖项,即 Unity、AutoFac、Ninject

interface IStringGenerator
{
    string GenerateNext();
}
class FixStringGenerator:IStringGenerator
{
  public FixStringGenerator(int length)
  {
   ...
  }
  public string GenerateNext()
  {
      ///logic
  }
...
}

并且对于 MinMax 字符串生成器 class 如下注入 FixStringGenerator

class MinMaxStringGenerator:IStringGenerator
{
    ....
     IStringGenerator _fixStringGenerator;
     public MinMaxStringGenerator(int minLength,int maxLength, IStringGenerator fixStringGenerator)
     {
        _fixStringGenerator=fixStringGenerator;
     }
    string GenerateNext()
    {
     /// do the things with fix generator "_fixStringGenerator"
    }
    ....
 }

@Mostafa,依赖注入需要通过实例注册这两个实现,以便它可以创建各自的实例。 HOW TO DI named instance with constructor injection

有关 DI 的更多信息 another link