Problem
Ostatnio dużo czytałem o tym, że Singletony są złe i jak lepsze jest wstrzykiwanie zależności (które rozumiem jako „używanie interfejsów”). Kiedy zaimplementowałem część tego z wywołaniami zwrotnymi / interfejsami / DI i przestrzegając zasady segregacji interfejsu, skończyło się to dość bałaganem.
Zależności rodzica interfejsu użytkownika były w zasadzie połączone ze wszystkimi jego elementami potomnymi, więc im wyżej w hierarchii był element interfejsu użytkownika, tym bardziej rozdęty był jego konstruktor.
Na szczycie hierarchii interfejsu użytkownika znajdowała się klasa aplikacji, zawierająca informacje o bieżącym wyborze i odniesienie do modelu 3d, który musi odzwierciedlać zmiany. Klasa aplikacji wdrożyła 8 interfejsów, a to dopiero około jedna piąta nadchodzących produktów (/ interfejsów)!
Obecnie pracuję z singletonem zawierającym bieżący wybór i elementy interfejsu mające funkcję aktualizacji. Ta funkcja spływa po drzewie interfejsu użytkownika i elementach interfejsu użytkownika, a następnie w razie potrzeby uzyskuje dostęp do bieżącego singletonu wyboru. W ten sposób kod wydaje mi się czystszy.
Pytanie
Czy singleton może być odpowiedni dla tego projektu?
Jeśli nie, to czy jest jakaś podstawowa wada w moim myśleniu i / lub implementacji DI, co czyni ją tak uciążliwą?
Dodatkowe informacje o projekcie
Typ: Koszyk na zakupy do mieszkań, z dzwonkami i gwizdkami
Rozmiar: 2 osobo-miesiące na kod i interfejs użytkownika
Utrzymanie: Brak bieżących aktualizacji, ale może później „wersja 2.0”
Środowisko: Używanie C # w Unity, który używa encji System elementów
W prawie wszystkich przypadkach interakcja użytkownika wyzwala kilka działań. Na przykład, gdy użytkownik wybierze element
- część interfejsu użytkownika pokazująca ten element i jego opis musi zostać zaktualizowana. W tym celu musi również uzyskać informacje z modelu 3d w celu obliczenia ceny.
- w dalszej części interfejsu należy zaktualizować ogólną cenę całkowitą
- należy wywołać odpowiednią funkcję w klasie na modelu 3d, aby wyświetlić tam zmiany
źródło
Odpowiedzi:
Myślę, że pytanie jest objawem, a nie rozwiązaniem.
Rozwiązanie szukające problemu; to i nieporozumienie prawdopodobnie psuje projekt. Czy przeczytałeś to SO pytanie o DI vs Singleton, różne koncepcje czy nie? Przeczytałem, że to po prostu opakowanie singletonu, aby klient nie musiał sobie radzić z singletonem. It.is.just.good.old.encapsulation. Myślę, że to jest na miejscu.
Najpierw zbuduj mniejsze bity, a następnie przekaż je konstruktorowi rzeczy, do której należą, i przekaż tę większą rzecz konstruktorowi kolejnej większej rzeczy ...
Jeśli masz skomplikowane problemy konstrukcyjne, użyj wzoru fabrycznego lub konstruktora. Najważniejsze jest to, że złożona konstrukcja jest wciągnięta we własną klasę, aby inne klasy były schludne, czyste, zrozumiałe itp.
To brzmi jak brak możliwości rozszerzenia. Brak projektu rdzenia i wszystko jest wbijane od góry. Powinna istnieć większa oddolna konstrukcja, skład i dziedziczenie.
Zastanawiam się, czy twój projekt jest „top heavy”. Wygląda na to, że staramy się, aby jedna klasa była wszystkim lub czymkolwiek innym, czym mogłaby być. A fakt, że jest to klasa interfejsu użytkownika, a nie klasa domeny biznesowej, naprawdę sprawia, że zastanawiam się nad oddzieleniem problemów.
Zrewiduj swój projekt od samego początku i upewnij się, że istnieje solidna, podstawowa abstrakcja produktu, na której można zbudować bardziej złożone lub różnej kategorii produkcje. W takim razie lepiej mieć niestandardowe kolekcje tych rzeczy, aby mieć gdzieś umieścić funkcjonalność „na poziomie kolekcji” - jak wspomniany „trzeci model”.
Wiele z nich może mieścić się w niestandardowych klasach kolekcji. Może być również niezależną strukturą klasową ze względu na głębię i złożoność. Te dwie rzeczy nie wykluczają się wzajemnie.
Przeczytaj o strukturze odwiedzin. Jest to pomysł, aby całe uchwyty funkcjonalności były podłączone abstrakcyjnie do różnych typów.
Projektowanie i DI
90% wszystkich zastrzyków zależności, jakie kiedykolwiek wykonasz, to przekazanie parametrów konstruktora. Tak mówi quy, który napisał książkę . Zaprojektuj dobrze swoje klasy i unikaj zanieczyszczenia tego procesu myślowego z niejasnym pojęciem o potrzebie użycia kontenera DI. Jeśli potrzebujesz, Twój projekt zasugeruje ci to, że tak powiem.
Skoncentruj się na modelowaniu domeny zakupów mieszkań.
Unikaj podejścia Jessiki Simpson do projektowania : „Zupełnie nie wiem, co to znaczy, ale chcę tego”.
Następujące są po prostu złe:
źródło
„Hierarchia klas” jest trochę czerwoną flagą. Hipotetyczny: strona internetowa z 5 widżetami. Strona nie jest przodkiem żadnego z widżetów. Może zawierać odniesienie do tych widżetów. Ale to nie jest przodek. Zamiast dziedzicznej klasy, rozważ użycie kompozycji. Każdy z 5 widżetów można zbudować osobno, bez odniesienia do innych widżetów lub strony głównej. Strona główna jest następnie konstruowana z wystarczającą ilością informacji, aby zbudować stronę podstawową i rozmieścić przekazane do niej obiekty widżetów (Kolekcja). Strona odpowiada za układ itp., Ale nie za konstrukcję i logikę widżetów.
Po użyciu kompozycji DI jest twoim najlepszym przyjacielem. DI pozwala zamienić każdy widżet na dowolną wersję lub typ widżetu zdefiniowany w DI. Budowa widżetów jest przechwytywana w DI i jest oddzielna od strony głównej. Być może nawet skład Kolekcji można zdefiniować w DI. Strona główna wykonuje układ w oparciu o przekazane do niej widżety, tak jak powinna. Nie są wymagane żadne zmiany w konstruktorze strony głównej. Strona główna potrzebuje tylko logiki do wykonania układu widżetów i przekazania informacji do / z widżetu w oparciu o zdefiniowane interfejsy.
Zamiast przepuszczać słuchaczy w górę iw dół łańcucha kompozycji, wstrzyknij kolekcję słuchaczy do tych widżetów, które tego potrzebują. Wstrzyknij kolekcję do wydawcy, aby mógł opublikować w kolekcji. Wstrzyknij kolekcję do słuchaczy, aby mogli dodać się do kolekcji. Kolekcja obejmuje wszystkie obiekty w łańcuchu kompozycji.
źródło