W tym wpisie przybliżę Ci jeden z najważniejszych wzorców w programowaniu, który jest niezależny od języka – wstrzykiwanie zależności.
Wstrzykiwanie zależności – prosty przykład
Załóżmy, że mamy dom, a w nim okna:
public class House { List<Window> windows = new ArrayList<>(); public static void main(String[] args) { } }
Przez okno możemy zerknąć i zobaczyć, jaką mamy pogodę.
class Window { private Weather weather; public Window() { this.weather = new Weather(); } public void lookOut() { System.out.println(this.weather.description); } }
public class Weather { private static Random random = new Random(System.currentTimeMillis()); public String description; public Weather() { switch(random.nextInt(4)) { case 0: this.description = "Pada deszcz"; break; case 1: this.description = "Świeci słońce"; break; case 2: this.description = "Pada śnieg"; break; case 4: this.description = "Wieje wiatr"; break; } } }
Następnie w klasie House utwórzmy konstruktor, a w nim cztery okna. Później dodajmy metodę, która wypisze nam jaka jest za nimi pogoda.
public class House { List<Window> windows = new ArrayList<>(); public House() { windows.add(new Window()); windows.add(new Window()); windows.add(new Window()); windows.add(new Window()); } public void look() { for(Window window : windows) { window.lookOut(); } } public static void main(String[] args) { } }
Teraz w metodzie main
zbudujmy nowy dom i sprawdźmy pogodę.
public class House { List<Window> windows = new ArrayList<>(); public House() { windows.add(new Window()); windows.add(new Window()); windows.add(new Window()); windows.add(new Window()); } public void look() { for(Window window : windows) { window.lookOut(); } } public static void main(String[] args) { House house = new House(); house.look(); } }
Gdy odpalimy nasz program okaże się, że za każdym oknem jest inna pogoda, co jest dość niepokojące.
Dzieje się tak dlatego, że w każdym z okien tworzymy nowy obiekt odpowiadający za pogodę, przez co za każdym razem losowany jest nowy opis.
W takiej sytuacji mówimy, że klasa Weather
jest zależnością klasy Window
.
Tutaj z pomocą przyjdzie nam dependencji injection, czyli wstrzykiwanie zależności.
Mianowicie nie będziemy tworzyć obiektu Weather w każdym oknie, lecz będzie on przekazywany do konstruktora z zewnątrz. Takie przekazywanie zależności z zewnątrz nazywamy wstrzykiwaniem.
class Window { private Weather weather; public Window(Weather weather) { this.weather = weather; } public void lookOut() { System.out.println(this.weather.description); } }
Następnie nowy obiekt odpowiadający za pogodę tworzymy w miejscu gdzie tworzymy nowe okna, czyli w tym wypadku w domu. My jednak przeniesiemy to jeszcze wyżej. Nie ma sensu, by w trakcie budowy domu tworzyć pogodę bo jest to twór niezależny.
public class House { List<Window> windows = new ArrayList<>(); public House(Weather weather) { windows.add(new Window(weather)); windows.add(new Window(weather)); windows.add(new Window(weather)); windows.add(new Window(weather)); } public void look() { for(Window window : windows) { window.lookOut(); } } public static void main(String[] args) { Weather weather = new Weather(); House house = new House(weather); house.look(); } }
I w tym momencie za każdym z okien panuje taka sama pogoda. Wszystkie okna używają w swoich operacjach tego samego obiektu odpowiedzialnego za pogodę, czyli tego wstrzykniętego w konstruktorze klasy House
Jest to tak zwane wstrzykiwanie poprzez konstruktor.
Istnieje jeszcze drugi typ wstrzykiwania – poprzez metodę.
Pogoda ma to do siebie, że lubi się zmieniać. Ustawianie jej na sztywno w konstruktorze nie wystarcza, więc musimy mieć możliwość jej zmiany.
public class House { List<Window> windows = new ArrayList<>(); public House(Weather weather) { windows.add(new Window(weather)); windows.add(new Window(weather)); windows.add(new Window(weather)); windows.add(new Window(weather)); } public void setWeather(Weather weather) { this.weahter = weather; } public void look() { for(Window window : windows) { window.lookOut(); } } public static void main(String[] args) { Weather weather = new Weather(); House house = new House(weather); house.look(); } }
Czyli stosujemy najprostszego w świecie settera i mamy szumnie brzmiące wstrzykiwanie poprzez metodę 🙂
I to tyle. Tylko tyle i aż tyle. Wstrzykiwanie zależności bez żadnych dodatków. Frameworki takie jak Spring ułatwiają wstrzykiwanie zależności – poprzez użycie DI wraz ze wzorcem object pool oraz adnotacjami. Dzięki tym dwóm dodatkom dzieje się „automagia” natomiast sedno wstrzykiwania zależności działa tak jak przedstawione powyżej, tylko w tle.
By być na bieżąco i mieć realny wpływ na tematykę tworzonych artykułów zapraszam do dołączenia do mojego newslettera.
W ostatnim fragmencie kodu klasa House ma zdefiniowaną metode setWeather(Weather weather),ale tak naprawdę nie jest nigdzie użyta a wstrzyknięcie przez konstruktor w kodzie pozostało. Czy to jest finalny efekt jaki chciałeś uzyskać?