Suppose I have MasterPackage
containing a Master
class, and BlasterPackage
containing Blaster
class. Since Master
needs a Blaster
to work, the higher level MasterPackage
depends directly on lower-level BlasterPackage
.
Using classic Dependency Inversion, one would add IBlaster
(or AbstractBlaster
) to MasterPackage
, thus inverting dependency between the packages.
But while facing this problem, I realized I could create a third package - let's name it MasterBlasterInterfaces
- and put IBlaster
there. That would "delegate" the dependency to that third, common package, and the original two packages would be now decoupled from one another.
But then, if I have a higer-level package called ThunderDome
, it will have to deal directly with BlasterPackage
, wouldn't it? I feel like it sort of violates encapsulation, while with direct dependency Master
could possibly abstract away the very existence of Blaster
.
So the question is:
Is there a good set of criteria to choose between inversion vs. delegation of dependencies? And how one vs. other impacts use of the packages by higher-level application layers?
1 Answer 1
Inverting the dependency as you have described it is only OK if you control the other package, and if this direct dependency is acceptable. For a lot of software, that is entirely OK. But most obviously, this doesn't work if your BlasterPackage
is an external library you rely on.
The magic of introducing an IBlaster
interface is that MasterPackage
and BlasterPackage
can work together without having a direct dependency relationship, and without being written by the same person/team/organization. Usually, this is not done by putting IBlaster
into a separate package that both modules depend on. Instead, IBlaster
would be part of MasterPackage
, and you would introduce an adapter module. The dependencies can be illustrated like this:
The adapter depends on both packages, but the Master
only depends on IBlaster
. Such adapters get extremely useful when writing unit tests, and wanting to mock out the BlasterPackage
. Of course, the MasterPackage
will require some conforming adapter to be provided, but there is no concrete dependency on the BlasterAdapter
. Even when you make all dependencies explicit and configurable, at some point the interface consumers and interface providers will have to be connected (dependency injection).
-
Nice! So do you thing it is correct to say that
ThunderDome
module, using aMaster
class, could also inject theBlaster
dependency into it? And what would be a sensible way for theThunderDome
module to get/create an instance ofBlaster
in the first place? Mind that am not currently using any dependency injection / IoC framework, and don't plan to do so unless unavoidable.heltonbiker– heltonbiker2015年12月15日 15:32:44 +00:00Commented Dec 15, 2015 at 15:32
Explore related questions
See similar questions with these tags.