Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is mixing constructor-based and setter-based injections a bad thing?

I have a class for products import from CSV file operation which requires about 7 parameters. This is an info which is definitely needed for importer.

All of this parameters have the same life time. In the end we must have an Immutable Object.

I was too scared to list all of them in constructor because of its affect to readability and decided to move 3 of them to setters injection. But obviously it's not an elegant solution.

Questions:

1) Is mixing constructor-based and setter-based injections a bad practice?

2) How this particular problem can be solved?

I was thinking about applying "Introduce Parameter Object" refactoring by Martin Fowler, but there is a problem with this.

4 Parameters can be moved to Parameter object quite easily (customerId, projectId, languageId etc.) - all integers.

Other 3 parameters are an object I inject(it is required for Mock unit-tests).

like image 643
Nikita Fedyashev Avatar asked Dec 31 '09 14:12

Nikita Fedyashev


People also ask

What happens if we use both setter injection and constructor injection?

Overriding: Setter injection overrides the constructor injection. If we use both constructor and setter injection, IOC container will use the setter injection. Changes: We can easily change the value by setter injection. It doesn't create a new bean instance always like constructor.

Can I do setter and constructor injection both on the same bean explain?

In Summary, both Setter Injection and Constructor Injection have their own advantages and disadvantages. The good thing about Spring is that it doesn't restrict you to use either Setter Injection or Constructor Injection and you are free to use both of them in one Spring configuration file.

When should we go for setter injection and constructor injection?

Constructor-based DI fixes the order in which the dependencies need to be injected. Setter-based DI helps us to inject the dependency only when it is required, as opposed to requiring it at construction time. Spring code generation library doesn't support constructor injection so it will not be able to create proxy.

Which is better setter injection and constructor injection?

To make it simple, let us say that we can use constructor based dependency injection for mandatory dependencies and setter based injection for optional dependencies. It is a rule of thumb!! Let's say for example. If you want to instantiate a class you always do it with its constructor.


1 Answers

It's not necessarily a bad thing to mix Constructor Injection and Property Injection, but it may not be that common. As an overall strategy, avoid Property Injection since it's much more difficult to implement correctly (this may sound counter-intuitive, but it's true).

It's important to understand when to use each pattern.

  • Constructor Injection should be your default injection pattern. It's super-easy to implement and can guarantee invariants: assign it to a read-only field to ensure the consumer's invariants.
  • Property Injection can be used when you have a good Local Default implementation, but you want to follow the Open/Closed Principle and allow advanced users to extend the class by providing an alternative implementation.

You should never apply Property Injection because of constructor cosmetics.

When you require too many dependencies, it's a sign that you may be violating the Single Responsibility Principle - the class is simply trying to do too much at once.

Instead of introducing a Parameter Object (otherwise a good suggestion), a better option is to encapsulate two or more of the dependencies into an aggregating service that orchestrates the interaction of these dependencies.

Imagine that your initial constructor looks like this:

public MyClass(IDep1 dep1, IDep2 dep2, IDep3 dep3, IDep4 dep4, IDep5 dep5)

After applying a bit of analysis, you figure out that in this case IDep1, IDep3 and IDep4 will be used together in a particular way. This will allow you to introduce an aggregation service that encapsulated these like this:

public class AggService : IAggService
{
    public AggService(IDep1 dep1, IDep3 dep3, IDep4 dep4)
    {
        // ...
    }

    // ...
}

You can now rewrite the original constructor to this:

public MyClass(IAggService aggSrvc, IDep2 dep2, IDep5 dep5)

and so forth...

It is very common that the aggregate service turns out to be a proper concept in it's own right, and suddenly you have a richer API than when you started.

like image 129
Mark Seemann Avatar answered Nov 16 '22 01:11

Mark Seemann