Skip to content

Breaking Circular Dependency between Components

Last updated on March 28, 2019

Introduction

Couple of days ago, I came across a piece of code that was not just tightly coupled but also formed a circular dependency among the components. In the following code, I’ve tried to give you a gist of it (may not be the best though). The below code has two key components, DataProvider and DataValidator. The DataProvider “new” DataValidator and passes in its own instance, which is then used to fetch data, making them very tightly coupled to each other.

public class DataValidator
{
	private DataProvider _dataProvider;
	public DataValidator(DataProvider dataProvider)
	{
		_dataProvider = dataProvider;
	}
	
	public bool ValidateData()
	{
		var dataReceived = _dataProvider.GetData();
		return dataReceived > 0 ? true : false;
	}
}

public class DataProvider
{	
	public bool ValidateData()
	{
		return new DataValidator(this).ValidateData();
	}
	
	public bool ProcessData()
	{
		// some data processing here
		return true;
	}
	
	public int GetData()
	{
		// return some raw data
		return 1;
	}
}

public class Program
{
	public static void Main()
	{
		var dataProvider = new DataProvider();
		bool success = dataProvider.ValidateData();
		if(success)
		{
			dataProvider.ProcessData();
			Console.WriteLine("success");
		}
		else
		        Console.WriteLine("error");
	}
}

 

Circular Dependency Problem

In the above code sample, DataProvider needs DataValidator to perform some data validation. However, the later in turn needs the DataProvider to retrieve that data. This will work fine unless DataValidator needs one or more additional components. This is to to say that, if we are to add one more dependency in DataValidator then we will have to wire it up to the hierarchy which is DataProvider.

Imagine, that the service performing the validations now wants to log all the errors and for that it has a dependency on ILogger. In that case, if we are to add that dependency, the components will look like this:

public class DataValidator
{
    private DataProvider _dataProvider;
    private ILogger _logger;

    public DataValidator(DataProvider dataProvider, ILogger logger)
    {
        _dataProvider = dataProvider;
        _logger = logger;
    }

    public bool ValidateData()
    {
        var dataReceived = _dataProvider.GetData();
        var validData = dataReceived > 0 ? true : false;

        if (!validData)
            _logger.Log("Invalid data received.");

        return validData;
    }
}

public class DataProvider
{	
    ...
    public bool ValidateData()
    {
        var dataValidator = new DataValidator(this, new Logger());
        return dataValidator.ValidateData();
    }
    ...
}

Because the two components are tightly wired, the dependency on ILogger has to be injected up the hierarchy as:

var dataValidator = new DataValidator(this, new Logger());

As a result, the DataProvider has an additional responsibility of instantiating ILogger and providing it to DataValidator, while creating its instance.

 

The Solution

Since the two components need to talk to each other, there has to be a way to do so without having circular dependency. Surprisingly, there is a way – using EventHandlerThe proposal is, that DataValidator will raise the event “DataRequired”, prior to performing any data validation operation. DataProvider, on the other hand, will subscribe to this event and will respond by providing the data. 

The following code shows the use of EventHandler, in order to break the circular dependency:

public class DataValidator
{
    private ILogger _logger;

    public event EventHandler DataRequired;
    public int Data { get; set; }

    public DataValidator(ILogger logger)
    {
        _logger = logger;
    }

    public bool ValidateData()
    {
        DataRequired?.Invoke(this, EventArgs.Empty);
        return Data > 0 ? true : false;
    }
}

public class DataProvider
{
    private DataValidator _dataValidator;
    public DataProvider(DataValidator dataValidator)
    {
        _dataValidator = dataValidator;
        _dataValidator.DataRequired += GetData;
    }

    public bool ValidateData()
    {
        return _dataValidator.ValidateData();
    }

    public bool ProcessData()
    {
        // some data processing here
        return true;
    }

    public void GetData(object sender, EventArgs e)
    {
        // set Data property in DataValidator
        _dataValidator.Data = 1;
    }
}

public class Program
{
    public static void Main()
    {
        // we can use a DI container, 
        // instead of 'newing' the components here
        var dataProvider = new DataProvider(new DataValidator(new Logger()));
        bool success = dataProvider.ValidateData();
        if (success)
        {
            dataProvider.ProcessData();
            Console.WriteLine("success");
        }
        else
            Console.WriteLine("error");
    }
}

 

Summary

To sum up, the DataValidator no longer has a dependency on DataProvider. It simply raises an event when it requires data, and any one who has subscribed to this event will respond.

This is one way of breaking circular dependency between components. Of course there may be a better solution, which I would love to learn about. So, do share!

Published inDesign Patterns & Principles