You take a non-testable class with a lot of static dependencies and expose, and expose until they are all explicitly declared in a constructor
But halfway through that nice plan, you notice your constructor gets big. Having many args in a function (let’s see constructors as a special type of function) is bad too
Some may suggest the builder pattern, but I’m still not 100% convinced one is allowed to throw in the build()
method (all of those dependencies are mandatory)
What should you do?
The standard advice is, “When your constructor gets big, it means the class has a lot of responsibilities, split it”. But I don’t see how I can split it! It really needs all of those
We have a dialog class that deals with vaccines (it is a bit like a form that a nurse fills in before administering a vaccine, I reckon). It had a lot of static calls that performed DB operations (still has). I moved some of those dependencies to the constructor(s), and now it already has three dependencies beside string ids (I’ll omit those)
public VacDlg(VaccineDao vaccineDao, InfectionDao infectionDao, VaccinationDao vaccinationDao) {
I may go on, and it’ll also have SchemeDao
, ActDao
, maybe even SexDao
If we used Hibernate or a similar framework, I could retrieve all the data with fewer DAOs (maybe, even one) as DAOs (repositories) would be connected to each other similarly to how the corresponding tables are. But we don’t
And by the way, if you wonder why a dialog class has dependencies on DAOs at all, it’s because we don’t have a clear separation between the frontend, backend, and data layers. The frontend communicates with the DB directly. The backend code mostly resides in the DB but also in the frontend
And those are just DAOs. I’m sure it has other hidden dependencies as well
That’s going to be a lot of args! I don’t want to replace one mess with mess of another kind
3
You seem to be injecting repositories in what appears to be a frontend component. That suggest that the responsibility of your “dialog” component is much, much deeper than what a “dialog” is.
I can’t even see its implementation and by your description of its signature alone it appears that this is responsible for the entire interaction from the user’s input down to it being persisted in the database, with only a repository layer inbetween.
The issue here should not be a concern about the amount of dependencies being injected and the syntax that follows from it. Your concern here should be about the amount of responsibilities that you’re baking into this single class.
The number of dependencies required in this class is merely a symptom of the disease.
It appears you’re already aware of this:
And by the way, if you wonder why a dialog class has dependencies on DAOs at all, it’s because we don’t have a clear separation between the frontend, backend, and data layers.
But you seem to be taking the stance that acknowledging it somehow resolves it as being a problem. It doesn’t. The problem you’re pointing at here stems from you expecting the dialog class to also orchestrate everything down to the persistence layer.
Additionally, and this is really not the main thing you should be focusing on but still relevant to point out; the issue that “avoid methods with too many parameters” points out is one of complexity for the developer who has to write the consuming code that calls those methods.
Dependency injection tends to happen via a container that acts as an automatic factory that looks at the constructor’s parameters and resolves those dependencies automatically, thereby completely sidestepping the need for humans to call the constructor themselves in most cases (other than your test suite, but that’s a separate topic).
3
I never understood the “method/class with too many arguments” argument, it could be said that having many arguments implies the method/class has more that a single responsibility that is strange, the method/class has a single responsibility that to fulfill requires information from different sources. Shape drawing requires shape coordinates, line thickness, line color, line type (dotted, dashed, continuous), line transparency, shadowing. What way could all these information be split to comply with not having too many arguments?
Nevertheless to avoid being drawn into an unnecessary argument there is one sole solution, a blend of parameter object and factory design pattern. That is a specialised factory to manufacture the dependencies required by a certain method/class and pass the instance of that factory parameter object while calling the method/class constructor.
You are missing the ViewModel layer I mentioned in my last answer.
VaccineDialogueViewModel
{
Vaccine vaccine
Infection infection
Vaccination vaccination
}
Now you can populate this in your (client side) controller and pass to the Dialogue component
Also, please lose the DAOs
tbh though, I think you are doing something wrong in the larger methodology of your programming, which we haven’t been shown. It might be that you are trying to apply MVC or MVVM to a framework which isn’t designed to support them.
7