Is the Dependency Inversion Principle dependent on having interfaces?

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());

Answer №1

It appears that there may be some confusion between the concepts of the Dependency Inversion Principle (DIP) and Dependency Injection. While they share similarities, they are distinct principles.

The DIP can be summarized as

"A. High-level modules should not depend on low-level modules. Both should depend on abstractions.

"B. Abstractions should not depend upon details. Details should depend upon abstractions."

- APPP, Jane Doe, Example Publisher, 2022

Within this context, an abstraction refers to encapsulation rather than a specific language feature such as an abstract class.

I was recently exploring the application of the DIP in various scenarios. For instance, consider a Ports and Adapters architecture where a Data Transfer Object (DTO) handles JSON serialization and deserialization, while a Domain Model contains business logic.

In adhering to the DIP, mapping methods between these two representations should reside within the DTO. This is because a mapping requires knowledge of both source and destination, with the DTO serving as an implementation detail. Placing these methods in the Domain Model would violate the principle by making the abstraction dependent on an implementation detail.

This scenario demonstrates how the DIP influences software architecture decisions, showcasing the use of pure functions for mapping without relying on polymorphism.

In contrast, Dependency Injection often utilizes polymorphism to facilitate the interchangeability of implementations. This can be achieved through interfaces, abstract classes, or other language-specific features like function pointers.

If you're interested in further exploration of this topic, I recommend checking out another insightful answer that delves deeper into these concepts.

Lastly, when defining interfaces solely for unit testing purposes, it's advisable to limit them to 'real' application dependencies, as discussed in this informative post on the subject.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

When working with Node.js functions, it is essential to keep in mind that the return value must be provided. However

Sorry for the confusing title, let me clarify In my node.js project, I am utilizing express-form along with a custom validation function as shown below: app.post('/register', form( field("username").trim().required().custom(function(value) ...

Rails, implementing a user-friendly form with Simple Form and a dynamic show/hide functionality

Utilizing simple form within my Rails 4 application. I have separate models for projects, scopes, and data. The projects model accepts nested attributes for scopes, while scopes accept nested attributes for data. In the new project form, I include a que ...

Limit the text input area in HTML to a fixed size, preventing any text from exceeding the specified boundary

Is there a way to create a fixed line text area that limits the user from typing beyond a certain number of lines and maximum width? My current CSS styling for this is as follows: .area-style { resize: none; width: 324px; height: 200px; m ...

Capture a section of the body background to incorporate into the canvas space

As a newcomer to the world of canvas, I have been learning from various sources about how it works. However, my goal is more dynamic and unique than what I've seen so far. I am looking to create a body background for my webpage that is responsive, cen ...

Angular method $http.get is failing to function as intended

This is the HTML and JavaScript code I have written. <!DOCTYPE html> <html ng-app> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title></title> <meta name ...

Reasons Behind the News Not Being Retrieved Using [XML JS Query]

Can you help me troubleshoot my code? <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width"> <title>News Site</title> <script> window.document.onload = ...

Leveraging npm for the development of my TypeScript/Node.js project

I'm facing challenges working on a project written in TypeScript and running on Node. I am finding it difficult to write the npm script to get it up and running properly for development purposes. What I am attempting to achieve is: clear the /dist f ...

Tips for utilizing the 'map' function with nested arrays within an array (JSON)

Below is the JSON data provided: users = [{ "name": "alex", "id":123, "surname":"xx", tarriff: { "id":1, "name":"free" } }, { "name": "tom", "id":124, "surname":"henry", tarriff: { "id":1, "name": ...

What is the best way to maintain a continuous and stable connection to MySQL in a Node.js environment

I've been working on developing a Discord Bot and I'm using MySQL for data storage. However, I've been facing an issue where the connection dies after a few hours. I was hoping someone might have some insight on how to resolve this. Here is ...

Instead of relying on the instanceof operator, opt for type checking on strings

If I have a library that handles TCP connections and the responses can vary, with some representing errors. Using an Error object may not be the best approach as it is expensive, and the stack trace wouldn't necessarily relate to the original request ...

Processing of an array received via AJAX and passed to a PHP script, inside a separate function in a different file

I have a JavaScript array that I am sending via AJAX to a PHP file named aux.php. What I want is for this array to be visible and manipulable within a function inside a class in another PHP file called payments.php. I've provided all the code so they ...

The 'HttpEvent<Student[]>' type cannot be directly assigned to the 'Student[]' type. Likewise, the 'HttpSentEvent' type is also not compatible with the 'Student[]' type

Issue TS2322 (TS) The type 'HttpEvent' cannot be assigned to the type 'Student[]'. The type 'HttpSentEvent' cannot be assigned to the type 'Student[]'. The property 'length' is missing in the &a ...

Angular 7 is throwing an error message stating that it is unable to locate the module named './auth.service'

Currently, I am facing a challenge while using Angular Guards to secure my pages from unauthorized access. import { ActivatedRouteSnapshot, CanActivate, RouterStateSnapshot , Router } from '@angular/router'; import { Observable } from 'rxjs& ...

Steps to retrieve a file following an AJAX request

Is it possible to automatically download a file following an AJAX call? Currently, when I make the AJAX request, it redirects me to the resource instead of initiating the file download. This is the AJAX function I am using: $('.download').click ...

Tips on incorporating a child component into a parent component using React and TypeScript

I am trying to conditionally render a child component within a parent component using React and TypeScript. Here is the code I have: const Parent = ({ prop1, prop2 }: { prop1: Prop1, prop2: Prop2; }) => { const isChecked = true; return ( ...

Navigating to a different component with react-bootstrap-table-next?

I have a collection of coding challenges in a table format. I want the user to be able to click on a challenge name and be routed to a separate page showcasing the details of that specific problem using a Problem component with unique props. Currently, I ...

Determine the success of an SQL query in Node.js

I've created a basic API using nodejs to connect my Flutter app with a SQL Server database, but I have a question. How can I verify if the query was successful in order to return different results? I'm attempting an update after a successful in ...

Tips for achieving an eye-catching text and image layout on a single page of your Wordpress blog

I've been exploring ways to achieve a design concept for my blog layout. I envision having the text and thumbnail displayed side by side, each taking up 50% of the width until the image reaches its end. Once the image ends, I want the text to span the ...

The combination of Autodesk Forge Viewer and React with TypeScript provides a powerful platform for developing

I'm brand new to React and Typescript, and I have a very basic question. In the viewer documentation, extensions are defined as classes. Is it possible to transform that class into a typescript function? Does that even make sense? For example, take th ...

What is the best way to dynamically update a variable in React JS by utilizing the Date() function in the background?

My code is designed to increase the value of the strong variable every 10 seconds in the background using the Date() module import React, { useState, useEffect } from "react"; export default function App() { const [strong, setStrong] = useStat ...