Dependency inversion principle — Zasada odwróconej zależności
Wysokopoziomowe moduły nie powinny zależeć od modułów niskopoziomowych, lecz zależność powinna wynikać z abstrakcji.
Jak wykorzystywać w praktyce DIP?
Twórzmy dużo abstrakcyjnych bytów. Każda klasa niech implementuje interfejs lub dziedziczy po klasie abstrakcyjnej. Tworząc oprogramowanie, możemy najpierw stworzyć tylko interfejsy, a dopiero później je zaimplementować.
Pomocne w spełnieniu tej zasady jest przestrzeganie tych reguł:
- Każda zmienna w klasie jest referencja do abstrakcji.
- Wszystkie klasy dziedziczą po abstrakcji.
- Żadna klasy potomna nie przesłania metod z klasy bazowej.
- Ustawianie zmiennych realizowane jest przez wzorzec fabryki lub wstrzykiwania zależności.
Przykład
Poniżej mamy klasę pokazującą raport. Dane do raportu brane są za bazy danych. Implementacja wygląda następująco:
class Program { static void Main(string[] args) { var reportImporter = new ReportDatabaseImporter(); var reportPresenter = new ReportPresenter(reportImporter); reportPresenter.ShowReport(); } } internal class ReportPresenter { private readonly ReportDatabaseImporter importer; public ReportPresenter(ReportDatabaseImporter importer) { this.importer = importer; } public void ShowReport() { Console.WriteLine(importer.GetReportData()); } } internal class ReportDatabaseImporter { public string GetReportData() { return "Report from Database"; } }
Po jakimś czasie dostaliśmy prośbę o wyświetlanie danych również z pliku Excel w taki sam sposób. Niestety, nie jesteśmy w stanie zrobić tego łatwo. Musimy zmienić klasę prezentującą raport. Takie rozwiązanie pozwala nam dodawać łatwiej kolejne źródła raportu:
using System; namespace SRP.Bad { class Program { static void Main(string[] args) { var reportImporter = new ReportDatabaseImporter(); var reportPresenter = new ReportPresenter(reportImporter); reportPresenter.ShowReport(); var reportImporter2 = new ReportExcelImporter(); var reportPresenter2 = new ReportPresenter(reportImporter2); reportPresenter2.ShowReport(); } } internal class ReportPresenter : IReportPresenter { private readonly IReportImporter importer; public ReportPresenter(IReportImporter importer) { this.importer = importer; } public void ShowReport() { var reportData = importer.GetReportData(); Console.WriteLine(reportData.GetContent()); } } internal class ReportDatabaseImporter : IReportImporter { public IReportData GetReportData() { return new ReportData("Report from Database"); } } internal class ReportExcelImporter : IReportImporter { public IReportData GetReportData() { return new ReportData("Report from Excel"); } } internal class ReportData : IReportData { private readonly string content; public ReportData(string content) { this.content = content; } public string GetContent() { return content; } } internal interface IReportData { string GetContent(); } internal interface IReportImporter { IReportData GetReportData(); } internal interface IReportPresenter { void ShowReport(); } }
Mamy tutaj dużą liczbę interfejsów. Ułatwiają one jednak rozwój aplikacji oraz testowanie. W testach będziemy mogli pod interfejs podstawić mocka.
Wszystkie posty związane z mini projektem: Poznaj zasady SOLID i OOP:
- Początek mini projektu: Poznaj zasady SOLID i OOP
- SOLID
- S jak Single responsibility principle, czyli zasada jednej odpowiedzialności
- O jak Open-closed principle, czyli zasada otwarte/zamknięte
- L jak Liskov Substitution Principle, czyli zasada podstawień Barbary Liskov
- I jak Interface segregation principle, czyli Zasada segregacji interfejsów
- D jak Dependency Inversion Principle, czyli Zasada odwrócenia zależności
- CS jak Ćwiczenia Single responsibility principle, czyli zasada jednej odpowiedzialności
- CO jak Ćwiczenia Open/closed principle, czyli Zasada otwarte-zamknięte
- CL jak Ćwiczenia Liskov Substitution Principle, czyli zasada podstawień Barbary Liskov
- CI jak Ćwiczenia Interface segregation principle, czyli Zasady segregacji interfejsów
- CI jak Ćwiczenia Dependency Inversion Principle, czyli Zasada odwrócenia zależności
- Ćwiczenia z SOLID
- Podsumowanie połowy projektu: Poznaj zasady SOLID i OOP
- Ćwiczenia z SOLID — Kata
- OOP — Object Oriented Programming, czyli programowanie obiektowe
- OOP — Myślenie obiektowe
- OOP — Object Oriented Programming, czyli programowanie obiektowe — Modelowanie dziedziny
- KISS — Keep it simple, stupid, czyli Bez udziwnień zapisu, idioto (BUZI)
- Lod — Law of Demeter, czyli Prawo Demeter
- DRY — Don’t repeat yourself, czyli Nie powtarzaj się
- SLAP — Single Level of Abstraction Principle, czyli Pojedynczy poziom abstrakcji
- Composition Over Inheritance, czyli Kompozycja ponad dziedziczeniem
- Encapsulate what changes, czyli Ukrywaj zmieniające się rzeczy
- Podsumowanie projektu: Poznaj zasady SOLID i OOP
- Podsumowanie zasad SOLID i OOP
- Mini kurs: Poznaj zasady SOLID i OOP – Zapisz się!
- Praca cząstkowa w Metodzie Kanban
Źródła
Obraz główny
Materiały
- Czysta architektura — Robert C. Martin
- https://code.tutsplus.com/tutorials/solid-part-4-the-dependency-inversion-principle–net-36872
- https://lukaszkosiorowski.pl/programowanie/solid-zasada-odwracania-zaleznosci/
- http://tomaszjarzynski.pl/solid-czesc-5-zasada-odwrocenia-zaleznosci/
- http://devman.pl/pl/techniki/zasady-solid-5-zasada-odwrocenia-zaleznoscidependency-inversion/
- https://www.modestprogrammer.pl/solid-interface-segregation-principle-isp-wszystko-co-powinienes-wiedziec-o-zasadzie-segregacji-interfejsow