Congratulations on studying S.O.L.I.D. These are some of my favorite principles.
The Video
01:45:30 is not when the video deals with The Dependency Inversion Principle (that's 1:26:38). It's not even when it deals with Dependency Injection (that's 1:32:33 - accepting a dependency and 1:33:30 - injecting a dependency). 01:45:30 is when it deals with Dependency Injection Frameworks.
Your Code
Going from Original to My_modified_code, you remove FirstClass
and call Method()
on the OtherClass
instance stored in temp
as a tempClass
. This is a refactoring since it does not change the behavior of the program (except for the commented out Console.ReadKey()
). What is different is that rather than achieving polymorphism by composition and delegation in FirstClass
(much like the Strategy Pattern does) you are now achieving polymorphism by subclassing and inheritance under tempClass
(much like the Template Pattern).
What you've lost is the level of indirection that FirstClass
was providing. FirstClass
could have suppressed the Method()
call, could have changed what instance Method()
was called on at any time, and could even have called something else entirely.
You've also lost your one and only Dependency Injection. OtherClass
was being injected into FirstClass
as a tempClass
in main before. Now main is handling it directly.
But other than that, yeah it's behavior is pretty much the same. Understand that the intent here wasn't to write the simplest code that behaves as you want. It's to write code that will withstand changes without breaking.
Dependency Inversion Principle
This is about both high and low level modules/classes not depending on concrete classes, or details, whatever you want to call them. This is why we see new
only in main away from your client classes. Instead they depend on abstractions like tempClass
.
The reason for this is to protect against change. If details aren't known then details can change without affecting anything else. Anything you know about you have to care about.
Dependency Injection
This is how the details find their way into the client classes that don't know them except through their abstractions.
We used to just call injections "parameter passing" or "passing a reference around" but few people understood why it was important to do that. So Fowler invented a new word for it in an attempt to (well, to sell books, but also) make clear that this is prefered to clients constructing things themselves.
Construction
Your simple example has all the construction happen in main. It's important to know it doesn't have to only occur here. You can have many classes dedicated to constructing and injecting dependencies into clients. What is key is that clients should not know about them.
There are many creational patterns that can help with this. The original Gang of Four creational patterns are a start but we've come a long way since then. From Josh Bloch's builder pattern to Fluent Interfaces to internal Domain Specific Languages. It's changed the way we test, and the way we write SQL queries. These new creational patterns are also part of why Java 8 almost looks like a new language.
Tap into this power and you can hand tune the construction of your clients to suit your needs. If, instead, you'd rather throw a completely generic construction solution at the problem then read on.
Dependency Injection Frameworks - Rant
Contrary to popular belief, and much marketing propaganda, Dependency Injection Frameworks do not help you invert dependencies (a good design does that). They do not accept dependency injections (your client code, written in your native language, does that). No, what Dependency Injection Frameworks actually do for you is solve the construction problem.
They can solve this by making you push all knowledge of your client object graph into xml configuration files or by making you decorate your classes with (sometimes proprietary) noise that lets you autowire based on class name or type or whatever. Which to chose is the classic Configuration vs Convention debate. Do you want absolute control or do you not want to have to think?
The only thing a Dependency Injection Framework (DIF) has to do with Dependency Injection(DI) is communication. DI is how a DIF communicates the work it's done for your client classes as it builds them. We call this communication the injection.
In other words, DI is what the framework expects YOU to support and accept in your clients. You can support and accept DI with or without a framework. If you don't, the framework won't do you much good. Well, the framework might offer some hacky workarounds, but other than that...
Constructor, Setter, and Interface Injection are the three classic forms of injection that you don't need any proprietary framework magic to use. Your language can do them on it's own. The video used constructor injection at 1:32:33.
There are other forms of injection (annotations and reflection tricks come to mind), many of them proprietary. If you're not careful you can find yourself writing code that is, ironically, dependent on your particular Dependency Injection Framework. A situation that the Framework authors wouldn't mind at all. But your boss might.
The lesson of this rant is that using a Dependency Injection Framework is no substitute for understanding Dependency Injection (DI), or the Dependency Inversion Principle (DIP). Really, they're just a handy way to construct objects, and certainly not the only one.