Search code examples
c#dependency-injectionsolid-principles

Decoupling a class that depends on another class whose constructor takes an argument


I have been practicing how to write clean code using SOLID. I have also been using DI in my code to remove coupling but only through constructor injection. In the many cases I have used DI, I have only used it to call methods. What I do not understand yet is how to decouple when you have a dependent class whose constructor takes an argument inside another class. If var obj = new A(month) creates dependency and tight coupling inside class B, how do I decouple/abstract this? Is this where the interface with property comes in? If so, how do I use it here?

public class A 
{
    private string _month;
    public A(string month) 
    {
        _month = month;
    }
}

public class B 
{
    public List<A> ListOfMonths;
    public B() 
    {
        ListOfMonths = new List<A>();
    }

    public List<A> SomeMethod() 
    {
        string[] months = new [] 
        {
            "Jan",
            "Feb",
            "Mar"
        };

        foreach(var month in months) 
        {
            var obj = new A(month); // If this is coupling, how do I remove it?
            ListOfMonths.Add(obj)
        }

        return ListOfMonths;
    }
}

Solution

  • If you want to decouple, you need to remove any reference to A from B and replace them by IA (interface similar to A) which is a placeholder for any class which would replace A.

    In the constructor of B you then provide a factory able to create instances of IA. You go further by placing an abstract factory which means you provide an interface of a factory capable of creating instances of IA.

    Here is a sample based on your code:

        public interface IA
        {
        }
    
        public interface IAFactory
        {
            IA BuildInstance(string month);
        }
    
        public class AFactory : IAFactory
        {
            public IA BuildInstance(string month)
            {
                return new A(month);
            }
        }
    
        public class A : IA
        {
            public A(string month)
            {
            }
        }
    
        public class B
        {
            private readonly IAFactory factory;
            public List<IA> ListOfMonths;
    
            public B(IAFactory factory)
            {
                this.factory = factory;
                ListOfMonths = new List<IA>();
            }
    
            public List<IA> SomeMethod()
            {
                string[] months = new[] {"Jan", "Feb", "Mar"};
                foreach (var month in months)
                {
                    var obj = factory.BuildInstance(month);
                    ListOfMonths.Add(obj);
                }
    
                return ListOfMonths;
            }
        }