Dependency Injection – How to Avoid Too Many Interfaces in UI

cdependency-injectionsingleton

Problem
I recently read a lot about Singletons being bad and how dependency injection (which I understand as "using interfaces") is better. When I implemented part of this with callbacks/interfaces/DI and adhering to the interface segregation principle, I ended up with quite a mess.

The dependencies of a UI parent where basically those of all its children combined, so the further up the hierarchy a UI element was, the more bloated its constructor was.

All the way on top of the UI hierarchy was an Application class, holding the info about the current selection and a reference to a 3d model which needs to reflect changes. The application class was implementing 8 interfaces, and this was only roundabout a fifth of the products (/ interfaces) to come!

I currently work with a singleton holding the current selection and the UI elements having a function to update themselves. This function trickles down the UI tree and UI elements then access the current selection singleton as needed. The code seems cleaner to me this way.

Question
Is a singleton maybe appropriate for this project?
If not, is there a fundamental flaw in my thinking and/or implementation of DI which makes it so cumbersome?

Additional info about the project
Type: Shopping basket for apartments, with bells and whistles
Size: 2 man-months for code and UI
Maintenance: No running updates, but maybe "version 2.0" later
Environment: Using C# in Unity, which uses an Entity Component system

In almost all cases, user interaction triggers several actions.
For example, when the user selects an item

  • the UI part showing that item and its description needs to be updated. For this, it also needs to get some info from a 3d model in order to calculate the price.
  • further up the UI, the overall total price needs to be updated
  • a corresponding function in a class on a 3d model needs to be called in order to display the changes there

Best Answer

I think the question is a symptom, not a solution.

I recently read a lot about Singletons being bad and how dependency injection (which I understand as "using interfaces") is better. When I implemented part of this with callbacks/interfaces/DI and adhering to the interface segregation principle, I ended up with quite a mess.

A solution looking for a problem; that and misunderstanding it probably is corrupting your design. Have you read this SO question about DI vs Singleton, different concepts or not? I read that as simply wrapping a singleton so the client does not have to deal with a singleton. It.is.just.good.old.encapsulation. I think that's spot on.


the further up the hierarchy a UI element was, the more bloated its constructor was.

Build the smaller bits first then pass them into the constructor of the thing they belong in and pass that bigger thing into the constructor of the next bigger thing...

If you've got complex construction issues, use the factory or builder pattern. Bottom line there is that complex construction pulled into it's own class to keep other classes neat, clean, comprehensible, etc.


The application class was implementing 8 interfaces, and this was only roundabout a fifth of the products (/ interfaces) to come!

This sounds like the absence of extend-ability. Core design is missing and everything is being crammed in from the top. There should be more bottom up construction, composition, and inheritance going on.

I wonder if your design is "top heavy." Sounds like we're trying to make one class be everything or anything that it could be. And the fact that it is a UI class, not a business domain class, that really makes me wonder about separation of concerns.

Revisit your design from the beginning and be sure there is a solid, basic product abstraction that can be built upon to make more complex or different category productions. Then you better have custom collections of these things so you have somewhere to put "collection level" functionality - like that "3rd model" you mention.


... 3d model which needs to reflect changes.

Much of this may fit in custom collection classes. It may also be independent class structure unto itself due to depth and complexity. These two things are not mutually exclusive.

Read about the visitor pattern. It's the idea of having whole chucks of functionality wired abstractly to different types.


Design and DI

90% of all the dependency injection you will ever do is constructor parameter passing. So says the quy who wrote the book. Design your classes well and avoid polluting that thought process with some vague notion about needing to use a DI container-thingy. If you need it, your design will suggest it to you so to speak.


Focus on modeling the apartment shopping domain.

Avoid the Jessica Simpson approach to design: "I totally don't know what that means, but I want it."

The following are just wrong:

  • I'm supposed to use interfaces
  • I'm not supposed to use a singleton
  • I need DI (whatever that is)
  • I'm supposed to use composition, not inheritance
  • I'm supposed to avoid inheritance
  • I need to use patterns
Related Topic