Dependency inversion was a software design principle, it just states
that how two modules should depend on each other. Now the
question comes, how exactly we are going to do it? The answer is
Inversion of control. Inversion of control is the actual mechanism
using which we can make the higher level modules to depend on
abstractions rather than concrete implementation of lower level modules.
So if I have to implement inversion of control in the above mentioned problem scenario, the first thing we need to do is to create an abstraction that the higher levels will depend on. So let us create an interface that will provide the abstraction to act on the notification received from
So now if I need to have the concrete classes for sending email and sms, these classes will also implement the same interface.
So if I have to implement inversion of control in the above mentioned problem scenario, the first thing we need to do is to create an abstraction that the higher levels will depend on. So let us create an interface that will provide the abstraction to act on the notification received from
AppPoolWacther
.public interface INofificationAction { public void ActOnNotification(string message); }
Now let us change our higher level module i.e. the AppPoolWatcher
to use this abstraction rather than the lower level concrete class.
class AppPoolWatcher { // Handle to EventLog writer to write to the logs INofificationAction action = null; // This function will be called when the app pool has problem public void Notify(string message) { if (action == null) { // Here we will map the abstraction i.e. interface to concrete class } action.ActOnNotification(message); } }So how will our lower level concrete class will change? how will this class conform to the abstraction i.e. we need to implement the above interface in this class:
class EventLogWriter : INofificationAction { public void ActOnNotification(string message) { // Write to event log here } }
So now if I need to have the concrete classes for sending email and sms, these classes will also implement the same interface.
class EmailSender : INofificationAction { public void ActOnNotification(string message) { // Send email from here } } class SMSSender : INofificationAction { public void ActOnNotification(string message) { // Send SMS from here } }So the final class design will look like:
So what we have done here is that, we have inverted the control to
conform to dependency inversion principle. Now our high level
modules are dependent only on abstractions and not the lower level
concrete implementations, which is exactly what dependency inversion
principle states.
But there is still one missing piece. When we look at the code of our
This is exactly where Dependency injection comes in picture. So its time to look at dependency injection in detail now.
But there is still one missing piece. When we look at the code of our
AppPoolWatcher
,
we can see that it is using the abstraction
i.e. interface but where exactly are we creating the concrete type and
assigning it to this abstraction. To solve this problem, we can do
something like:class AppPoolWatcher { // Handle to EventLog writer to write to the logs INofificationAction action = null; // This function will be called when the app pool has problem public void Notify(string message) { if (action == null) { // Here we will map the abstraction i.e. interface to concrete class writer = new EventLogWriter(); } action.ActOnNotification(message); } }But we are again back to where we have started. The concrete class creation is still inside the higher level class. Can we not make it totally decoupled so that even if we add new classes derived from INotificationAction, we don't have to change this class.
This is exactly where Dependency injection comes in picture. So its time to look at dependency injection in detail now.
No comments:
Post a Comment