首页 > 解决方案 > 在构造对象实例时,分离 DI 和数据参数的有效方法是什么?

问题描述

我正在尝试为需要将 DI(服务)和其他参数(数据模型)传递给类进行初始化的场景找到一个优雅的解决方案。

对于数据模型(简单的类和结构),我们可以这样做:

class Board
{
    public Dimension Dimension { get; }
    public Tile[] Tiles { get; }
    public Piece[] Pieces { get; }

    public Board(Dimension dimension)
    {
        Dimension = dimension;
        // Initialize Tiles here
        // Initialize Pieces here (not all tiles will have a piece)
    }

    public bool TryGetPiece(Tile tile, out Piece piece)
    {
        // Search for the piece...
        return true;
    }

    public bool TryMovePiece(Tile tileFrom, Tile tileTo)
    {
        // Try moving new piece...
        return true;
    }
}

在这里,我们不需要任何 DI。我们只是通过构造函数传递 Dimension 参数。

对于服务(纯粹的(如果这是正确的术语)),我们会这样做:

class PieceMovingService
{
    public PieceMovingService(AllKindsOfDiItems)
    {
        // DI items initialised here...
    }

    public void PerformBestMove(Board board)
    {
        // All kinds of thinking....
        // Still thinking...
        // Finally found where to move the piece to
        // Move the piece
        board.TryMovePiece(A, B);
    }

    public void SomeOtherRelatedStuff(Board board)
    {
        // Blah blah lah
    }
}

但有时我真的想将 Board 实例作为构造函数参数传递给 PieceMovingService 类(我也阅读并消化了这个构造函数参数与方法参数?):

class PieceMovingService
{
    public Board Board { get; }

    public PieceMovingService(AllKindsOfDiItems, Board board)
    {
        // DI items initialized here...
        Board = board;
    }

但是,我不喜欢将 DI 与此数据模型混合使用。我开始谷歌,发现这篇文章Combining DI with constructor parameters? 但公认的答案表明应该避免这种结构。不幸的是,这个答案对我来说似乎不完整。它只是不点击。

我也对通过构造函数传递 DI 的方法不满意。DI 论点对我来说有点“如何”的味道。这些是实现细节的一部分,如果我决定更改方法并且如果 DI 列表发生更改,则需要重构整个构造函数,并且项目中此类的所有实例都需要相应地重构。另一方面,Board 参数的传递考虑到它是要操作的主要对象,因此具有“什么”的味道;不管方法是如何实现的,这个对象仍然是必需的;没有它 PieceMovingService 没有任何意义。

我深思熟虑后决定将我的 DI 实例化为具有默认值的私有属性,这样我就不必在构造函数中传递它们。但在这种情况下,没有发生 IoC,我无法从外部传递任何其他东西。如果我将这些属性公开,我会解决这个问题,但我会引入副作用,因为我可以在同一个实例上一遍又一遍地更改这些 DI 项目并为方法获得不同的结果(出于某种原因,当 Board 依赖时我可以造成副作用,但当 DI 服务这样做时就不行了)。

此外,还有一个问题是某些 DI 需要自己的 DI,因此会导致丑陋的链接。

所以我一直在想......然后我想出了这个模式:

class A
{
    private Dependency1 dependency1;
    private Dependency2 dependency2;

    private A(int number)
    {

    }

    public class AFactory
    {
        private readonly Dependency1 dependency1;
        private readonly Dependency2 dependency2;

        public AFactory(Dependency1 dependency1, Dependency2 dependency2)
        {
            this.dependency1 = dependency1;
            this.dependency2 = dependency2;
        }

        public A Create(int number)
        {
            return new A(number)
            {
                dependency1 = dependency1,
                dependency2 = dependency2
            };
        }
    }
}

它解决了我之前解决的问题,但引入了另一个问题,现在我根本无法在没有工厂的情况下实例化 A 类。因此,我必须执行以下操作:

var aFactory = new AFactory(new Dependency1(), new Dependency2());
var a = aFactory.Create(5);

感觉它没有任何优势或任何东西,只是让它变得更麻烦。在这一点上,感觉就像在构造函数中混合 DI 和数据模型毕竟不是那么糟糕,这让我回到了方 1。

所以我的问题是:在构造对象实例时,分离 DI 和数据参数的有效方法是什么,这样类的用户就不必一直处理传递 DI 并且能够只关注“什么”,而不是“如何”?

标签: c#dependency-injectionconstructorinversion-of-controlfactory

解决方案


推荐阅读