Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Constructor injection overuse

I am looking for best practices of avoiding constructor injection overuse. For example I have Meeting entity which has few sub entities like shown below:

  • Meeting
    1. MeetingContacts
    2. MeetingAttendees
    3. MeetingType
    4. Address
    5. MeetingCompanies
    6. MeetingNotes

MeetingService class looks like below:

public class MeetingService
{
    private readonly IMeetingContactRepository _meetingContactRepository;
    private readonly IMeetingAttendeeRepository _meetingAttendeeRepository;
    private readonly IMeetingTypeRepository _meetingTypeRepository;
    private readonly IAddressRepository _addressRepository;
    private readonly IMeetingCompanyRepository _meetingCompanyRepository;
    private readonly IMeetingNoteRepository _meetingNoteRepository;
    private readonly IMeetingRepositoy _meetingReposity;

    public MeetingService(IMeetingRepositoy meetingReposity, IMeetingContactRepository meetingContactRepository, IMeetingAttendeeRepository meetingAttendeeRepository, 
        IMeetingTypeRepository meetingTypeRepository, IAddressRepository addressRepository, 
        IMeetingCompanyRepository meetingCompanyRepository, IMeetingNoteRepository meetingNoteRepository)
    {
        _meetingReposity = meetingReposity;
        _meetingContactRepository = meetingContactRepository;
        _meetingAttendeeRepository = meetingAttendeeRepository;
        _meetingTypeRepository = meetingTypeRepository;
        _addressRepository = addressRepository;
        _meetingCompanyRepository = meetingCompanyRepository;
        _meetingNoteRepository = meetingNoteRepository;
    }

    public void SaveMeeting(Meeting meeting)
    {
        meetingReposity.Save();
        if(Condition1())
            _meetingContactRepository.Save();
        if(Condition2())
            _meetingAttendeeRepository.Save();
        if(Condition3())
            _meetingTypeRepository.Save();
        if(Condition4())
            _addressRepository.Save();
        if(Condition5())
            _meetingCompanyRepository.Save();
        if(Condition6())
            _meetingNoteRepository.Save();
    }
    //... other methods
}

Here are just seven dependencies but real code contains much more of them. I used different techniques described in the "Dependency Injection Constructor Madness" but I have not found how to deal with repository dependencies.

Is there any way how I can reduce the number of dependencies and keep the code testable?

like image 361
k0stya Avatar asked Feb 21 '23 03:02

k0stya


1 Answers

Constructor overuse is just a symptom - it seems you are approximating a unit of work by having a "master" class that knows about the various elements of message persistence and plugs them into the overall save.

The downside is that each repository communicates its independence of the others by exposing a dedicated Save method; this is incorrect, though, as SaveMeeting explicitly states that the repositories are not independent.

I suggest identifying or creating a type that the repositories consume; this centralizes your changes and allows you to save them from a single place. Examples include DataContext (LINQ to SQL), ISession (NHibernate), and ObjectContext (Entity Framework).

You can find more information on how the repositories might work in a previous answer of mine:

Advantage of creating a generic repository vs. specific repository for each object?

Once you have the repositories, you would identify the context in which they would act. This generally maps to a single web request: create an instance of the common unit of work at the beginning of the request and hand it to all the repositories. At the end of the request, save the changes in the unit of work, leaving the repositories free to worry about what data to access.

This neatly captures and saves everything as a single unit. This is very similar to the working copy of your source control system: you pull the current state of the system into a local context, work with it, and save the changes when you're done. You don't save each file independently - you save them all at the same time as a discrete revision.

like image 166
Bryan Watts Avatar answered Mar 05 '23 19:03

Bryan Watts