1

I am trying to find an elegant solution to the scenario where both DI (services) and other arguments (data models) need to be passed to a class for its' initialisation.

For data models (simple classes and structs) we can do something like this:

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

Here we do not need any DI. We just pass the Dimension argument through the constructor.

For services (pure (if that's the right term)) we do something like this:

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

But sometimes I really want to pass the Board instance to the PieceMovingService class as a constructor argument (I read and digested this one as well Constructor Parameters vs Method Parameters?):

class PieceMovingService
{
    public Board Board { get; }

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

However I am not happy about mixing DI with this data model. I started to google and found this article Combining DI with constructor parameters? but the accepted answer states that this kind of structure should be avoided. Unfortunately this answer seems incomplete to me. It just doesn't click.

Also I am unhappy with the approach where the DI is passed via constructor. DI arguments have a flavour of "HOW" to me. These are the part of the implementation detail and if I'd decide to change the method and if DI list changes then the whole constructor needs to be refactored and all the instantiations of this class within the project need to be refactored accordingly. On the other hand the Board parameter is passed with the idea in mind that it is the main object to operate on, therefore has a flavour of "WHAT"; regardless of how methods are implemented this very object remains required; without it the PieceMovingService has no sense.

I gave it a thorough thought and decided to instantiate my DIs as private properties with default values so that I wouldn't have to pass these in a constructor. But in this case IoC is not happening, I am unable to pass anything else from the outside. If I made these properties public, I solve this problem but I introduce side effects because I can keep changing these DI items over and over again on the same instance and get different results for the methods (for some reason, I am OK when Board dependency causing side effects, but not OK when DI services do).

Furthermore, there is a problem where some of the DI require their own DI and therefore would result in ugly chaining.

So I kept thinking... Then I have came up with this pattern:

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

It solves the problems I've addressed eariler but introduces another one where now I am unable to instantiate the A class without a factory at all. And as a result I would have to do the following:

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

It feels like it doesn't have any advantage or whatsoever and just makes it more cumbersome. At this point it feels like mixing DI and data models in the constructor is not that bad after all, which sends me back to square 1.

So my question is: what is an efficient way of separating DI and data arguments when constructing an object instance so that the user of the class wouldn't have to deal with passing the DI all the time and would be able to focus just on "WHAT", not "HOW"?

  • 2
    You might be interested in [this blog post](https://blogs.cuttingedge.it/steven/posts/2015/code-smell-injecting-runtime-data-into-components/), which talks about separating data and behavior, or this longer series on [DI Composition Models](https://blogs.cuttingedge.it/steven/posts/2019/di-composition-models-primer/). – Steven Mar 05 '21 at 19:15

0 Answers0