Dependency Injection & Inversion of Control

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] what's up guys welcome to another video brought to you by the simple engineer in today's video we're gonna talk about the idea of inversion of control and dependency injection so before we get started let's just dive into what exactly a dependency is and let's assume that we have a Class A and a happens to use methods from another class a B so a relies on B that's exactly what a dependency is a has a dependency on B for its operation to be successful it needs to have some instance or some copy of B inside of it typically in software development you would have a class say we have a user class and that class needs to talk to a database like my sequel what you would commonly see is that user would initialize a my sequel database and proceed to call methods to store information what the inversion of control recognizes the relationship role between the dependencies should be reversed so instead of the user initializing or instantiating another object we would actually have a framework or somewhere higher up the dependency graph initialize the database instance for us and then pass it to us as a parameter therefore we relinquish all responsibility of this database object and somebody just hands it to us and that allows us to depend more on abstractions rather than concrete implementations which promotes loosely coupled architecture flexibility and plugg ability within our code another way that I like to think about inversion of control is think about a lamp you create a lamp when we're creating a user and we are hard-coding the database type that's analogous to creating a lamp and soldering the plug to the internal wiring of an outlet in order for you to rip that thing out and plug it into another outlet is going to be extremely difficult likewise as your software grows really really large and you have hard-coded your user objects to a specific concrete implementation of a database it's going to be hard to rip that out and refactor it in order to achieve this idea that brings us to dependency injection so instead of us new an object within our class we're going to have a framework like spring or we could write this ourselves which is what we'll do in a minute just initialize an object and then pass it down the dependency graph so it's actually given to us as a parameter and typically instead of relying on the hard-coded concrete implementations like my sequel Oracle specifically we rely on more abstract implementations for example an interface such as a database okay so I've written a really basic class here so let's quickly run through this I have a class called IOC it stands for inversion of control just a main method that initializes an instance of this class and to keep everything simple I've created my user and database classes in the same file so we have a user class it relies on my sequel database and the my sequel database essentially we're simulating a database it just persists some data well we need to actually initialize a user object here so we'll just say user user equals container new user and now we can just call user dot add and this is some data so now if we recompile the code you can see that my sequel has persisted this is some data now the issue here is actually twofold the first issue is that if we wanted to write unit tests for this user class it would be nearly impossible because we rely internally on a my sequel instance so therefore it's going to be really really hard to test the internals of this code because we can't pass in a mock instance of a database second if we wanted to actually rip ourselves away from the internal implementation of connecting to my sequel and utilize another database we can't do that because we've hard-coded our Association of this user to a my sequel database instance so what we need to do is we need to actually invert the control flow to say instead of me handling the creation and lifecycle of this database object I'm just gonna have somebody else do it for me and they're just gonna pass it in to my method and therefore I don't care about it anymore I just do what I was told to do and I use the instance of a database that was given to me so in order to invert the control flow we are going to passing a my sequel database we'll just call it database and now this becomes this database equals database of course we'll get a compilation failure because we need to pass in an instance of it so we'll just say new my sequel database we can rerun the code and just ensure that does exactly what it was told to do but now we get the benefit of testability we can write a unit test that actually mocks the instance of this database and then we can simulate this persistence call but still test the internals of this class so that's one huge benefit unfortunately the customer comes in and they say I want to use an Oracle database or a Postgres database so we come in here and let's imagine by the way that this this is a very large application so refactoring it can be very very tedious when we hard code assumptions like using a my sequel database here for instance so I'm gonna create a new Oracle database and it's just going to be called Oracle database and we will just say Oracle has persisted the data so we would hope that we would have really loosely coupled architecture we could come in here and just say new Oracle database and rerun the code unfortunately we get a compilation error because we don't support different types of databases we've hard-coded ourselves to a my sequel database what we need to do is we need to actually follow what the dependency inversion principle says it says that we need to rely on abstractions rather than concrete implementations and typically to follow suit with this principle we need to slap an interface in between this dependency graph so instead of having just these concrete types we need to get a little bit more generic and create something like an interface and we'll just call it database database we'll have a just a void method that's called persist and it takes in some string data and now we just need to say that this implements database and we can say this implements database as well so now what we can do is instead of write relying on concrete implementations we can rely on the more abstract type which in this case would be a database so we'll say database and we'll replace this with database as well now all of a sudden you see that the compilation error has gone away so we'll rerun this and now we get oracle has persisted some data we could replace this with my sequel my sequel database and run it and we get my sequel has persisted some data so now you see that we're having really really loosely coupled reliance upon these different database dependencies which allows us to have this type of plug ability and what we're doing up here this is dependency injection we are passing dependencies down the control graph rather than just kind of having this black box implementation not knowing what dependencies are being used further down that dependency graph let's talk about how frameworks like spring utilize dependency injection frameworks typically what happens is we initialize an object in some global context some application context and you can think of this almost like a singleton where we have one single instance of an object and typically it's it's configured at you know within like an XML file let's assume that this common tier is the XML configuration within our spring application and I'm gonna be very very generic on the syntax here because I don't want a tightly coupled to any particular framework I just want to elucidate the ideologies that these frameworks take advantage of essentially what you do is you create a global instance or a global context of a particular object so a lot of ways people do this like in spring is they'll create a bean they'll give it an ID so we'll call this like my sequel for example and then we'll give it the actual class pass so let's say that it's in the comm da ville' under my sequel so this right here would initialize this this object for us in a global context so we'd have a singleton available throughout our application we could do the same thing for Oracle as well so now we have a global instance of Oracle available throughout our application but this is where it gets interesting let's say that we have a bunch of different users bred throughout our application so in this case I'll just write 3 in this piece of the application but imagine that these users could be initialized in various places but the user the the user or programmer comes in here and they they need a modify user so they come in here and they say we need to actually add an database as a parameter so I come in here and I will call this database too and we will pass in another database reference call a database to and you've seen that in the code we've actually broken this completely this is really problematic because if we had initialized these user objects by hand a lot of places in our in our program we've broken the main API and that that can be really problematic so what dependency injection frameworks allow us to take advantage of is we could actually initialize this these user objects in one single place so I could come in here and I could say beam ID equals user I'll give it a class we'll call it com Java user for example and it will take in different different types of databases so in this case we take in two databases very generically and so what I we can do here we can pass in a reference type so we can say something like our graph equals and then we can pass in either to my sequel types or we could pass in you know a reference to this oracle type and these reference types are pointing to these already initialized beans and this is really really cool so now if I want to you know these are all basically the same user objects what I would do instead is I would get rid of this so I'm not actually managing the initialization here in my code either I come in here and I just add an annotation so like in spring I say Auto Wired and you can basically place this down the chain here and what spring will do is it will Auto initialize these user objects based on the beam that we have here and this is a really really good way to handle your dependencies so even though I've changed the parameters of this user constructor they're going to get auto wired and auto configured based on this context of our configuration this container management system that we use and it will inject the dependencies for us automatically so although we can do this manually this is some of the benefit that you get from utilizing a dependency injection container so that pretty much covers it if you guys have any questions feel free to leave a comment please subscribe and like the video thanks
Info
Channel: Ryan Schachte
Views: 182,885
Rating: undefined out of 5
Keywords: dependency Injection, dip, ioc, inversion of control, java, spring, springboot, code, clean architecture, bob martin, container, architecture, visual studio, c#, tutorial, easy, simple, object oriented, polymorphism
Id: EPv9-cHEmQw
Channel Id: undefined
Length: 11min 0sec (660 seconds)
Published: Fri Feb 08 2019
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.