After exploring various examples of Dependency Inversion in different programming languages, I have noticed a common theme.
// Class A depends on Class B
class A {
property;
constructor() {
this.property = (new B()).property;
}
}
new A();
Most instances utilize interfaces to achieve this concept.
From my perspective, interfaces (or abstract classes in some languages) primarily serve the purpose of aiding in testing. It appears that interfaces are necessary in many languages to allow testing frameworks to substitute a mocked version for testing purposes, rather than utilizing the original implementation.
interface Dependency {
property: string
}
class B implements Dependency { ... }
// Class A no longer relies on Class B
class A {
property;
constructor(interface: Dependency) {
this.property = interface.property;
}
}
new A(new B());
While interfaces also permit flexibility in using different implementations at runtime, in my coding experience, most classes require a specific dependency structure. I rarely find the need to implement another class that adheres to the same interface but offers different functionality. This aspect usually remains consistent over time.
In TypeScript unit testing, I am able to mock dependencies without interfaces through alternative methods. Since I typically only use one runtime implementation (as mentioned earlier), do interfaces truly play a vital role in upholding the Dependency Inversion principle?
Furthermore, is the essence of the Dependency Inversion principle in TypeScript (and even in JavaScript without strong types) as straightforward as the following example?
// Class A does not rely on Class B?
class A {
property;
constructor(b: B) {
this.property = b.property;
}
}
new A(new B());