Skip to content

Implicit vs Explicit Dependencies

Last updated on April 1, 2019

If our class depends upon other classes to complete its operations, then these other classes are dependencies for our class. Our class can have these dependencies as implicit or explicit dependencies. What does this mean? What effect does it have on our application design? Let’s try to find answers to these questions.

 

Implicit Dependencies

The dependencies are implicit for a class, if they exist only in the code within that class, and not in its public interface. Therefore, while instantiating our class, we will not be aware of any dependency that our class may have, to perform its operations. Consequently, our code may fail during execution.

Classes with implicit dependencies cost more to maintain than those with explicit dependencies. Also, they are more difficult to test because of their tight coupling with the collaborators. And the tight coupling among the classes and their collaborators, result in more rigid and brittle designs.

Example

class Program
{
    static void Main(string[] args)
    {
        decimal paidValue = 453.23m;
        var commerce = new Commerce();
        commerce.ProcessCustomerPayment(paidValue);
    }
}

public class Commerce
{
    public void ProcessCustomerPayment(decimal paidValue)
    {
        var currencyConverter = new CurrencyConverter();
        var paymentProcessorv = new PaymentProcessor();
        decimal currencyValue = currencyConverter.ConvertCurrency(paidValue);
        paymentProcessor.ProcessPayment(currencyValue);
        // do some work
    }
}

 

public class PaymentProcessor
{
    public void ProcessPayment(decimal value)
    {
        // do some work
    }
}

public class CurrencyConverter
{
    public decimal ConvertCurrency(decimal value)
    {
        //convert value to local currency and return
        return value;
    }
}

As we can see, the Commerce class is tightly coupled with the PaymentProcessor and CurrencyConverter. Also, at the time of object creation for Commerce class, we can not judge what all collaborators it is going to use. Further, we will see how we can refactor this code in order to achieve loose coupling.

 

Explicit Dependencies

Being explicit about its dependencies means, that a class exposes all its class-level dependencies in its constructor. However, more local ones may appear as method parameter list. It is due to the explicit declaration, that we are aware of all dependencies a class has, at the time of its object construction.

An explicit dependency is often declared as an interface in the class constructor. Consequently, the dependency can be easily swapped out with its other implementations, whether in production or during testing or debugging. This makes them much easier to maintain and far more open to accept any change.

Example

class Program
{
    static void Main(string[] args)
    {
        decimal paidValue = 453.23m;
        var commerce = new Commerce(new PaymentProcessor(), new CurrencyConverter());
        commerce.ProcessCustomerPayment(paidValue);
    }
}

public class Commerce
{
    IPaymentProcessor _paymentProcessor;
    ICurrencyConverter _currencyConverter;
        
    public Commerce(IPaymentProcessor paymentProcessor, ICurrencyConverter currencyConverter)
    {
        _paymentProcessor = paymentProcessor;
        _currencyConverter = currencyConverter;
    }

    public void ProcessCustomerPayment(decimal paidValue)
    {
        // do some work
        decimal currencyValue = _currencyConverter.ConvertCurrency(paidValue);
        _paymentProcessor.ProcessPayment(currencyValue);
    }
}
public interface IPaymentProcessor
{
    void ProcessPayment(decimal value);
}

public class PaymentProcessor : IPaymentProcessor
{
    public void ProcessPayment(decimal value)
    {
        // do some work
    }
}

public interface ICurrencyConverter
{
    decimal ConvertCurrency(decimal value);
}

public class CurrencyConverter : ICurrencyConverter
{
    public decimal ConvertCurrency(decimal value)
    {
        //convert value to local currency 
        return value;
    }
}

In this example, the Commerce class exposes all its required collaborators in its constructor. As a result, we have a loosely coupled application. Moreover, we now have the freedom to choose among different implementations of these interfaces required by the Commerce class. Consequently, the application is now easy to maintain, test and expand.

Published inCS Fundamentals