Jest to decyzja projektowa, która wydaje się często pojawiać: jak przekazać kontekst za pomocą metody, która jej nie potrzebuje, do metody, która to robi. Czy istnieje poprawna odpowiedź, czy zależy to od kontekstu.
Przykładowy kod, który wymaga rozwiązania
// needs the dependency
function baz(session) {
session('baz');
}
// doesn't care about the dependency
function bar() {
baz();
}
// needs the dependency
function foo(session) {
session('foo')
bar();
}
// creates the dependency
function start() {
let session = new Session();
foo(session);
}
Możliwe rozwiązania
- Threadlocal
- światowy
- obiekt kontekstowy
- przekazać zależność
- curry baz i przekaż go do paska z ustawioną zależnością jako pierwszy argument
- zastrzyk zależności
Przykłady gdzie pojawia się
Przetwarzanie żądań HTTP
Często używane są obiekty kontekstowe w postaci atrybutów żądania: patrz expressjs, Java Servlet lub owin .net.
Logowanie
Do logowania w Javie ludzie często używają globals / singletonów. Zobacz typowe wzorce logowania log4j / commons / java.
Transakcje
Lokalne wątki są często używane do utrzymywania transakcji lub sesji związanych z łańcuchem wywołań metod, aby uniknąć konieczności przekazywania ich jako parametrów do wszystkich metod, które ich nie potrzebują.
design-patterns
Jamie McCrindle
źródło
źródło
Odpowiedzi:
Jedyną uczciwą odpowiedzią jest to, że zależy to od idiomów twojego paradygmatu programistycznego. Jeśli używasz OO, prawie na pewno niepoprawne jest przekazywanie zależności między metodami. To zapach kodu w OO. W rzeczywistości jest to jeden z problemów, które rozwiązuje OO - obiekt naprawia kontekst. Tak więc w OO jednym poprawnym (zawsze istnieją inne sposoby) podejściem jest dostarczenie zależności za pośrednictwem podmiotu konstruktorskiego lub własności. Komentator wspomina o „wstrzykiwaniu zależności” i jest to całkowicie uzasadnione, ale nie jest to absolutnie konieczne. Wystarczy podać zależność, aby była dostępna jako członek dla
foo
ibaz
.Wspominasz o curry, więc założę, że programowanie funkcjonalne nie jest wykluczone. W takim przypadku filozoficznym odpowiednikiem kontekstu obiektowego jest zamknięcie. Każde podejście, które po raz kolejny naprawia zależność, dzięki czemu jest dostępne dla osób na utrzymaniu, działa dobrze. Curry to jedno z takich podejść (i sprawia, że brzmisz mądrze). Pamiętaj tylko, że istnieją inne sposoby zamknięcia zależności. Niektóre z nich są eleganckie, a niektóre okropne.
Nie zapomnij o programowaniu aspektowym . Wygląda na to, że w ostatnich latach popadł w niełaskę, ale jego głównym celem jest rozwiązanie dokładnie opisanego problemu. W rzeczywistości klasycznym przykładem aspektu jest logowanie. W AOP zależność jest dodawana automatycznie po napisaniu innego kodu. Ludzie AOP nazywają to „ tkaniem ”. Wspólne aspekty są wplecione w kod w odpowiednich miejscach. To sprawia, że twój kod jest łatwiejszy do myślenia i jest naprawdę fajny, ale także dodaje nowe obciążenie testowe. Będziesz potrzebował sposobu, aby ustalić, że twoje ostatnie artefakty są zdrowe. AOP ma na to również odpowiedzi, więc nie czuj się zastraszony.
źródło
Jeśli
bar
zależy od tegobaz
, co z kolei wymagadependency
, to takżebar
wymagadependency
prawidłowego użyciabaz
. Dlatego poprawnym podejściem byłoby albo przekazanie zależności jako parametrubar
, albo currybaz
i przekazanie tego dobar
.Pierwsze podejście jest prostsze do wdrożenia i odczytu, ale tworzy sprzężenie między
bar
ibaz
. Drugie podejście usuwa to połączenie, ale może skutkować mniej czytelnym kodem. To, które podejście jest najlepsze, będzie prawdopodobnie zależeć od złożoności i zachowania obu funkcji. Na przykład, jeślibaz
lubdependency
mają skutki uboczne, łatwość testowania będzie prawdopodobnie dużym czynnikiem decydującym o wyborze rozwiązania.Sugerowałbym, że wszystkie inne opcje, które proponujesz, są z natury „hackerskie” i mogą prowadzić do problemów zarówno z testowaniem, jak i trudnymi do wyśledzenia błędów.
źródło
dependency
przez parametry to wstrzykiwanie zależności?Mówiąc filozoficznie
Zgadzam się z troską Davida Arno .
Czytam OP jako szukam rozwiązań wdrożeniowych. Odpowiedzią jest jednak zmiana projektu . „Wzory”? Można powiedzieć, że projektowanie OO opiera się na kontekście. To rozległa, pusta kartka papieru w ciąży z możliwościami.
Radzenie sobie z istniejącym kodem to inny, dobrze, kontekst.
Pracuję teraz nad tym samym problemem. Cóż, naprawiam setki wierszy kodu kopiuj-wklej, co zostało zrobione tylko po to, aby można było wstrzyknąć wartość.
Zmodularyzuj kod
Wyrzuciłem 600 wierszy zduplikowanego kodu, a następnie refaktoryzowałem, więc zamiast „A wzywa B wzywa C wzywa D ...” Mam „Zadzwoń A, zwróć, Zadzwoń B, zwróć, Zadzwoń C ...”. Teraz musimy tylko wprowadzić wartość do jednej z tych metod, powiedzmy metoda E.
Dodaj domyślny parametr do konstruktora. Obecni dzwoniący nie zmieniają się - tutaj słowo opcjonalne jest „opcjonalne”. Jeśli argument nie zostanie przekazany, zostanie użyta wartość domyślna. Następnie zmienia się tylko 1 linia, aby przekazać zmienną do przebudowanej, modułowej struktury; i niewielka zmiana w metodzie E, aby z niej skorzystać.
Domknięcia
Wątek dla programistów - „Dlaczego program miałby używać zamknięcia?”
Zasadniczo wstrzykujesz wartości do metody, która zwraca metodę dostosowaną do tych wartości. Ta dostosowana metoda jest następnie wykonywana.
Ta technika pozwoli ci zmodyfikować istniejącą metodę bez zmiany jej podpisu.
źródło