Inverting the dependencies

The solution to these problems is to make EventStreamer work with an interface, rather than a concrete class. This way, implementing this interface is up to the low-level classes that contain the implementation details:

 

Now there is an interface that represents a generic data target where data is going to be sent to. Notice how the dependencies have now been inverted since EventStreamer does not depend on a concrete implementation of a particular data target, it does not have to change in line with changes on this one, and it is up to every particular data target; to implement the interface correctly and adapt to changes if necessary.

In other words, the original EventStreamer of the first implementation only worked with objects of type Syslog, which was not very flexible. Then we realized that it could work with any object that could respond to a .send() message, and identified this method as the interface that it needed to comply with. Now, in this version, Syslog is actually extending the abstract base class named DataTargetClient, which defines the send() method. From now on, it is up to every new type of data target (email, for instance) to extend this abstract base class and implement the send() method.

We can even modify this property at runtime for any other object that implements a send() method, and it will still work. This is the reason why it is often called dependency injection: because the dependency can be provided dynamically.

The avid reader might be wondering why this is actually necessary. Python is flexible enough (sometimes too flexible), and will allow us to provide an object like EventStreamer with any particular data target object, without this one having to comply with any interface because it is dynamically typed. The question is this: why do we need to define the abstract base class (interface) at all when we can simply pass an object with a send() method to it?

In all fairness, this is true; there is actually no need to do that, and the program will work just the same. After all, polymorphism does not mean (or require) inheritance to work. However, defining the abstract base class is a good practice that comes with some advantages, the first one being duck typing. Together with as duck typing, we can mention the fact that the models become more readable—remember that inheritance follows the rule of is a, so by declaring the abstract base class and extending from it, we are saying that, for instance, Syslog is DataTargetClient, which is something users of your code can read and understand (again, this is duck typing).

All in all, it is not mandatory to define the abstract base class, but it is desirable in order to achieve a cleaner design. This is one of the things this book is for—to help programmers avoid easy-to-make mistakes, just because Python is too flexible and we can get away with it.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.240.61