SOLID, the Repository Pattern, and Dependency Injection: One Complete Example, Every Principle Explained in Place
Two things get confused constantly: the Repository Pattern gets used without anyone explaining what it actually is, and Dependency Inversion (a design principle) gets treated as the same thing as Dependency Injection (a technique), when they're genuinely different ideas that happen to work together. This post explains both properly, then builds one complete example, a small library book…
The Repository Pattern is a class whose sole purpose is to interact with a data source - be it a database, API, file, or any other storage medium. Its function is to return straightforward objects, and it should never be directly accessed by the business logic, services, controllers, or any other part of the application.
Think of a librarian in an archive room. You don't need to know the internal organization of the shelves - alphabetical by genre, acquisition date, etc. You simply ask the librarian for the book you need, and they retrieve it for you. The librarian is the repository, abstracting away the complexity of the data source, allowing you to focus on your task instead.
Implementing the Repository Pattern involves defining an interface that outlines the methods you want to use to interact with the data source. For example, methods for getting a book by its ID, retrieving all available books, and reserving a book. Then, you would write a class that implements this interface, using the actual data source (like a database).
The Dependency Inversion Principle (DIP), on the other hand, is a design rule. It states that high-level code should depend on abstractions, not on concrete classes. This principle promotes loose coupling between components of an application, making them easier to maintain and test.
Dependency Injection (DI), while closely related, is a technique that implements the DIP. DI is the mechanism that actually makes DIP work in practice. Instead of a class creating its own dependencies directly, something external provides these dependencies to the class (usually through its constructor).
It's like the lamp analogy mentioned earlier. DIP is the rule that the lamp should plug into a standard wall socket, not have its wires directly wired to the wall. DI is the actual electrician who wires the socket and plugs the lamp in.
In the example of a library book reservation system, this pattern is demonstrated through the use of an interface (IBookRepository) for interacting with the database, and a concrete class (BookRepository) that implements this interface. The NotificationSender interface and its implementations (EmailNotificationSender, SmsNotificationSender) also follow this pattern. By abstracting away the data access and notification mechanisms, the system becomes easier to modify and test.
Written by urgent.news from Dev.to's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.