Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should I make concrete class dependencies explicit through constructor injection in my classes?

I am doing the design of a small project where I didn't use programming against interfaces for all my classes. I found that some classes would hardly ever be needed to change, so I let them be referenced by their client classes as concrete classes.

So, let's say we have ClassB that'll be consumed be consumed by ClassA:

alt text

class ClassB {
}

My question is, should I create ClassB in ClassA, or should I pass that responsability "up" in the hierarchy? I'll depict both cases:

class ClassA {
    private ClassB classB;

    public ClassA() {
        this.classB = new ClassB();
    }
}

or

class ClassA {
    private ClassB classB;

    public ClassA(ClassB classB) {
        this.classB = classB;
    }
}

I'd like to hear about how would you do it and what'd be the rationale behind it!

Thanks

like image 432
devoured elysium Avatar asked Oct 26 '10 06:10

devoured elysium


3 Answers

Some advantages of your first option (A creates B):

  1. The user of class A needs to know nothing about B or how to create & configure it. This makes for a simpler programming model.
  2. B can also be made private/internal, so that users of your library don't need to wade through lots of helper classes they don't need to see.
  3. You can change the way A works to not use B at all without breaking calling code.
  4. Encapsulation - no one gets to tamper with B from the outside while A is running

Some advantages of your second option (A takes a dependency on B):

  1. The user of class A has full control over the B object - they can configure it differently, they can pass the same one into multiple instances of A if they want.
  2. It opens the door for different implementations to be passed in (if B is an interface or base class) which is of great value for unit testing, or extensibility.
  3. update: if in the future, it becomes more complicated to create B (e.g. B has some dependencies of its own), then that can be managed outside without needing to make changes to A.

Note that it is also possible to create a "best of both worlds" solution by using what is sometimes called "poor man's dependency injection":

class ClassA {
    private ClassB classB;

    public ClassA(ClassB classB) {
        this.classB = classB;
    }

    public ClassA() : this(new ClassB()) {

    }
}
like image 174
Mark Heath Avatar answered Nov 15 '22 19:11

Mark Heath


It depends on the implementation, there is no general answer. If A has all the relevant data and knowledge to initialize B, then it could initialize it.

If you don't want A to know how to initialize B or you don't want to give A all the data for the initialization, then you should create it externally.

like image 20
testalino Avatar answered Nov 15 '22 19:11

testalino


you'd better inject interface which implemented by ClassB.

class ClassA {
private InterfaceB B;

public ClassA(InterfaceB B) {
    this.B = B;
}
}
class classB: InterfaceB
{
}

Please note that InterfaceB may be a regular class as base class for your derived ones. In this case it still works as interface.

like image 32
Arseny Avatar answered Nov 15 '22 18:11

Arseny