Podczas projektowania programu często dochodzę do momentu, w którym muszę przekazywać instancje obiektów przez kilka klas. Na przykład, jeśli mam kontroler, który ładuje plik audio, a następnie przekazuje go do odtwarzacza, a odtwarzacz przekazuje go do odtwarzacza Runner, który przekazuje go gdzie indziej itp. Wygląda to trochę źle, ale nie umieć tego uniknąć. Czy może to zrobić?
EDYCJA: Może przykład odtwarzacza nie jest najlepszy, ponieważ mógłbym załadować plik później, ale w innych przypadkach to nie działa.
źródło
Ciekawe, że nikt jeszcze nie mówił o Niezmiennych obiektach . Twierdziłbym, że przepuszczanie niezmiennego obiektu przez wszystkie różne warstwy jest w rzeczywistości dobrą rzeczą, zamiast tworzenia wielu krótkotrwałych obiektów dla każdej warstwy.
Na swoim blogu znajduje się kilka świetnych dyskusji na temat niezmienności Erica Lipperta
Z drugiej strony twierdzę, że przekazywanie obiektów zmiennych między warstwami jest złym projektem. Zasadniczo budujesz warstwę z obietnicą, że otaczające ją warstwy nie zmienią jej w sposób, aby złamać kod.
źródło
Przekazywanie instancji obiektów jest normalną czynnością. Zmniejsza to potrzebę utrzymywania stanu (tj. Zmiennych instancji) i oddziela kod od kontekstu wykonywania.
Jednym z problemów, które możesz napotkać, jest refaktoryzacja, kiedy musisz zmienić podpisy wielu metod w łańcuchu wywołań w odpowiedzi na zmieniające się wymagania parametrów metody w dolnej części łańcucha. Można to jednak złagodzić za pomocą nowoczesnych narzędzi programistycznych, które pomagają w refaktoryzacji.
źródło
Może niewielki, ale istnieje ryzyko przypisania tego odniesienia gdzieś w jednej z warstw, co może później spowodować zawieszenie odniesienia lub wyciek pamięci.
źródło
Jeśli przekazujesz obiekty po prostu dlatego, że jest to potrzebne w odległym obszarze kodu, użycie odwrócenia wzorców projektowych wstrzykiwania kontroli i zależności oraz opcjonalnie odpowiedniego kontenera IoC może dobrze rozwiązać problemy dotyczące przenoszenia instancji obiektów. Użyłem go w średnim projekcie i nigdy więcej nie rozważyłbym napisania dużego fragmentu kodu serwera bez jego użycia.
źródło
Przekazywanie danych przez wiązkę warstw nie jest złą rzeczą, to naprawdę jedyny sposób, w jaki system warstwowy może działać bez naruszania struktury warstwowej. Znakiem są problemy, gdy przekazujesz dane do kilku obiektów na tej samej warstwie, aby osiągnąć swój cel.
źródło
Szybka odpowiedź: Nie ma nic złego w przekazywaniu instancji obiektów. Jak również wspomniano, należy pominąć przypisywanie tego odniesienia do wszystkich warstw, potencjalnie powodując wiszące odniesienie lub wycieki pamięci.
W naszych projektach wykorzystujemy tę praktykę do przekazywania DTO (obiektu przesyłania danych) między warstwami i jest to bardzo pomocna praktyka. Ponownie wykorzystujemy również nasze obiekty dto, aby raz bardziej skomplikować budowę, na przykład w celu uzyskania informacji podsumowujących.
źródło
Jestem przede wszystkim twórcą interfejsu WWW, ale wydaje mi się, że twój intuicyjny dyskomfort może być mniej związany z przekazywaniem instancji, a bardziej z faktem, że masz trochę proceduralne z tym kontrolerem. Czy kontroler powinien pocić wszystkie te szczegóły? Dlaczego odwołuje się nawet do nazwy więcej niż jednego innego obiektu do odtwarzania dźwięku?
W projektowaniu OOP mam tendencję do myślenia w kategoriach tego, co jest wiecznie zielone i co może ulec zmianie. Przedmiotem zmian jest to, co będziesz chciał umieścić w swoich większych obiektach, aby zachować spójne interfejsy, nawet gdy gracze się zmieniają lub dodaje się nowe opcje. Lub też chcesz hurtowo zamienić obiekty audio lub komponenty.
W takim przypadku kontroler musi stwierdzić, że istnieje potrzeba odtworzenia pliku audio, a następnie mieć spójny / wiecznie zielony sposób na jego odtworzenie. Z drugiej strony elementy odtwarzacza audio mogą łatwo ulec zmianie wraz ze zmianą technologii i platform lub dodaniem nowych opcji. Wszystkie te szczegóły powinny znajdować się pod interfejsem większego obiektu złożonego, IMO, i nie powinno być konieczne przepisywanie kontrolera, gdy zmieniają się szczegóły dotyczące odtwarzania dźwięku. Następnie, gdy przekazujesz instancję obiektu ze szczegółami, takimi jak lokalizacja pliku, do większego obiektu, wszystko to zamiana odbywa się we wnętrzu odpowiedniego kontekstu, w którym ktoś jest mniej skłonny zrobić z nim coś głupiego.
Więc w tym przypadku nie sądzę, że to rzucanie instancją obiektu może być dla ciebie problemem. Chodzi o to, że kapitan Picard biegnie do maszynowni, aby włączyć rdzeń osnowy, biegnie z powrotem do mostu, aby wyznaczyć współrzędne, a następnie naciska przycisk „uderz go” po włączeniu osłon, zamiast po prostu powiedzieć „Weź nas na planetę X w Warp 9. Zrób to. ” i pozwalając swojej załodze uporządkować szczegóły. Ponieważ, gdy sobie z tym poradzi, może kapitanem każdego statku we flocie, nie znając układu każdego statku i tego, jak wszystko działa. I to ostatecznie największa wygrana w projektowaniu OOP, do której strzelać, IMO.
źródło
To dość powszechny projekt, który się dzieje, chociaż możesz mieć problemy z opóźnieniami, jeśli twoja aplikacja jest wrażliwa na tego typu rzeczy.
źródło
Ten problem można rozwiązać za pomocą dynamicznie zmienianych zmiennych, jeśli ma je Twój język, lub lokalnej pamięci wątków. Mechanizmy te pozwalają nam powiązać niektóre zmienne niestandardowe z łańcuchem aktywacyjnym lub wątkiem kontroli, abyśmy nie musieli przekazywać tych wartości do kodu, który nie ma z nimi nic wspólnego, aby można je było przekazać do innego kodu który ich potrzebuje.
źródło
Jak wskazały inne odpowiedzi, nie jest to z natury zły projekt. Może tworzyć ścisłe sprzężenie między klasami zagnieżdżonymi i tymi, które je zagnieżdżają, ale rozluźnienie sprzężenia może nie być prawidłową opcją, jeśli zagnieżdżenie odniesień zapewnia wartość dla projektu.
Jednym z możliwych rozwiązań jest „spłaszczenie” zagnieżdżonych odniesień w klasie kontrolera.
Zamiast kilkakrotnie przekazywać parametr przez zagnieżdżone obiekty, można zachować w klasie kontrolera odwołania do wszystkich zagnieżdżonych obiektów.
To, jak dokładnie zostanie to zaimplementowane (lub nawet jeśli jest to prawidłowe rozwiązanie), zależy od aktualnego projektu systemu, takiego jak:
Jest to problem, który napotkałem we wzorcu projektowym MVC dla klienta GXT. Nasze komponenty GUI zawierały zagnieżdżone komponenty GUI dla kilku warstw. Kiedy dane modelu zostały zaktualizowane, ostatecznie przerzuciliśmy je przez kilka warstw, aż dotarły do odpowiednich komponentów. Stworzyło to niepożądane połączenie między komponentami GUI, ponieważ jeśli chcieliśmy, aby nowa klasa komponentów GUI akceptowała dane modelu, musieliśmy stworzyć metody aktualizacji danych modelu we wszystkich komponentach GUI, które zawierały nową klasę.
Aby to naprawić, utrzymaliśmy w klasie View mapę odniesień do wszystkich zagnieżdżonych komponentów GUI, aby za każdym razem, gdy dane modelu były aktualizowane, widok mógł wysyłać zaktualizowane dane modelu bezpośrednio do komponentów GUI, które tego potrzebowały, koniec historii . Działa to dobrze, ponieważ były tylko pojedyncze wystąpienia każdego komponentu GUI. Widziałem, że nie działa tak dobrze, jeśli wystąpiło wiele wystąpień niektórych składników GUI, co utrudnia określenie, która kopia wymaga aktualizacji.
źródło
To, co opisujesz, to tak zwany wzorzec projektowania łańcucha odpowiedzialności . Apple wykorzystuje ten wzorzec do obsługi swojego systemu zdarzeń i do tego, ile jest wart.
źródło