Próbuję dobrze zrozumieć, jak zaimplementować dobre oddzielenie interfejsu użytkownika od modelu, ale mam problem z ustaleniem, gdzie dokładnie podzielić linie.
Patrzyłem na Model-View-Presenter, ale nie jestem pewien, jak dokładnie go wdrożyć. Na przykład mój widok ma wiele okien dialogowych.
- Czy powinna istnieć klasa View z instancjami każdego z okien dialogowych? W takim razie, w jaki sposób okna dialogowe powinny współdziałać z Prezenterem? to znaczy. jeśli indywidualne okno dialogowe musi żądać danych z Modelu za pośrednictwem Prezentera, w jaki sposób dialog powinien uzyskać odniesienie do Prezentera? Przez odniesienie do widoku podanego mu podczas budowy?
- Myślałem, że może widok powinien być klasą statyczną? Następnie okna dialogowe GetView i stamtąd prezentera ...
- Myślałem o skonfigurowaniu Prezentera z właścicielem Widoku i Modelu (w przeciwieństwie do Widoku posiadającego Prezentera i Prezentera posiadającego Model) oraz Prezentera rejestrującego wywołania zwrotne dla zdarzeń w Widoku, ale to sprawia, że wydaje się to dużo bardziej sprzężone (lub przynajmniej zależne od języka).
Staram się:
- uczyń to możliwie jak najbardziej oddzielonym
- idealnie umożliwiają para Prezenter / model z widokiem innych językach (ja nie zrobiłem mnóstwo inter-językowego rzeczy, ale wiem, że jest to możliwe, szczególnie tym bardziej
void(void)
mogę trzymać się przynajmniej C # app z Biblioteka C ++ ... - utrzymuj kod w czystości i prostocie
Więc ... jakieś sugestie, jak należy obsługiwać interakcje?
design-patterns
ui
interfaces
próbuj złapać
źródło
źródło
Odpowiedzi:
Witamy na śliskim stoku. W tym momencie zdałeś sobie sprawę, że istnieje nieskończona różnorodność wszystkich interakcji między widokiem modelu. MVC, MVP (Taligent, Dolphin, Passive View), MVVM, żeby wymienić tylko kilka.
Wzorzec Prezentera widoku modelu, podobnie jak większość wzorów architektonicznych, jest otwarty na wiele różnorodności i eksperymentów. Jedną wspólną cechą wszystkich wariantów jest rola prezentera jako „pośrednika” między widokiem a modelem. Dwa najczęstsze to widok pasywny i nadzorujący prezenter / kontroler - [ Fowler ]. Widok pasywny traktuje interfejs użytkownika jako bardzo płytki interfejs między użytkownikiem a prezenterem. Zawiera bardzo mało, jeśli w ogóle, logiki, która przenosi tyle odpowiedzialności na prezentera. Nadzór nad prezenterem / kontrolerempróbuje wykorzystać powiązanie danych wbudowane w wiele platform interfejsu użytkownika. Interfejs użytkownika obsługuje synchronizację danych, ale prezenter / kontroler wkracza, aby uzyskać bardziej złożoną logikę. W obu przypadkach model, widok i prezenter tworzą triadę
Istnieje wiele sposobów, aby to zrobić. Bardzo często postrzegane jest to przez traktowanie każdego okna dialogowego / formularza jako innego widoku. Wiele razy istnieje stosunek 1: 1 między widokami a prezenterami. To nie jest trudna, szybka zasada. Dość często zdarza się, że jeden prezenter obsługuje wiele powiązanych widoków i odwrotnie. Wszystko zależy od złożoności widoku i złożoności logiki biznesowej.
Jeśli chodzi o sposób, w jaki widoki i prezenterzy uzyskują odniesienia do siebie, jest to czasami nazywane okablowaniem . Masz trzy możliwości:
Widok zawiera odniesienie do prezentera
Formularz lub okno dialogowe implementuje widok. Formularz ma procedury obsługi zdarzeń, które są przekazywane do prezentera za pomocą bezpośrednich wywołań funkcji:
Ponieważ prezenter nie ma odniesienia do widoku, widok musi przesłać mu dane jako argumenty. Prezenter może komunikować się z widokiem za pomocą funkcji zdarzeń / wywołań zwrotnych, których widok musi nasłuchiwać.
Prezenter posiada odniesienie do widoku
W scenariuszu widok przedstawia właściwości danych, które wyświetla użytkownikowi. Prezenter nasłuchuje zdarzeń i manipuluje właściwościami w widoku:
Oba zawierają odniesienia do siebie, tworząc zależność cykliczną. Z
tym scenariuszem łatwiej jest pracować niż z innymi. Widok reaguje na zdarzenia, wywołując metody w prezencie. Prezenter odczytuje / modyfikuje dane z widoku poprzez odsłonięte właściwości.
Istnieją inne kwestie, które należy wziąć pod uwagę przy wzorcach MVP. Kolejność tworzenia, czas życia obiektu, w którym odbywa się okablowanie, komunikacja między triadami MVP, ale ta odpowiedź urosła już wystarczająco długo.
źródło
Jak wszyscy powiedzieli, jest mnóstwo opinii i żadna z nich nie jest dobra ani zła. Bez wchodzenia w niezliczoną liczbę wzorców i skupianie się wyłącznie na MVP, oto kilka sugestii dotyczących implementacji.
Trzymaj je oddzielnie. Widok powinien implementować interfejs, który tworzy więź między widokiem a prezenterem. Widok tworzy prezentera i wstrzykuje się do prezentera oraz przedstawia metody oferowane prezenterowi do interakcji z widokiem. Widok odpowiada za wdrożenie tych metod lub właściwości w dowolny sposób. Zasadniczo masz jeden widok: jeden prezenter, ale w niektórych przypadkach możesz mieć wiele widoków: jeden prezenter (web, wpf itp.). Kluczem tutaj jest to, że prezenter nie wie nic o implementacjach interfejsu użytkownika i tylko wchodzi w interakcję z widokiem przez interfejs.
Oto przykład. Najpierw mamy klasę widoku z prostą metodą wyświetlania wiadomości użytkownikowi:
Teraz jest prezenter. Zauważ, że prezenter pobiera IView do swojego konstruktora.
Oto rzeczywisty interfejs użytkownika. Może to być okno, okno dialogowe, strona internetowa itp. Nie ma znaczenia. Uwaga: konstruktor widoku utworzy prezentera, wstrzykując się do niego.
Prezenter nie dba o to, jak widok implementuje metodę, którą właśnie wykonuje. Jak wszyscy prezenter wie, może to być zapisywanie do pliku dziennika, a nawet nie pokazywanie go użytkownikowi.
W każdym razie prezenter trochę pracuje z modelem na zapleczu i w pewnym momencie chce poinformować użytkownika o tym, co się dzieje. Więc teraz mamy gdzieś w prezencie metodę, która woła do widoku wiadomości InformUser.
To tutaj dostajesz swoje oddzielenie. Prezenter ma tylko odniesienie do implementacji IView i tak naprawdę nie obchodzi go, jak jest on implementowany.
Jest to również słaba implementacja mans, ponieważ w widoku masz odniesienie do Prezentera, a obiekty są ustawiane za pomocą konstruktorów. W bardziej niezawodnym rozwiązaniu prawdopodobnie chciałbyś spojrzeć na odwrócenie kontenerów kontroli (IoC), takich jak Windsor, Ninject itp., Które rozwiązałyby dla ciebie implementację IView w czasie wykonywania na żądanie, a tym samym uczyniłyby ją jeszcze bardziej oddzieloną.
źródło
Myślę, że ważne jest, aby pamiętać, że kontroler / prezenter to miejsce, w którym akcja naprawdę ma miejsce. Sprzężenie w sterowniku jest nieuniknione ze względu na konieczność.
Podstawowym punktem kontrolera jest to, że jeśli wprowadzisz zmianę w widoku, wówczas model nie musi się zmieniać i odwrotnie (jeśli model się zmienia, widok nie musi albo), ponieważ kontroler tłumaczy Modeluj w widoku iz powrotem. Ale kontroler zmieni się, gdy zrobią to zmiany modelu lub widoku, ponieważ musisz skutecznie tłumaczyć w kontrolerze, jak model ma być oglądany, jak wprowadzić zmiany wprowadzone w widoku z powrotem do trybu.
Najlepszy przykład, jaki mogę podać, to to, że kiedy piszę aplikację MVC, mogę nie tylko mieć dane w widoku GUI, ale mogę także napisać procedurę, która wypycha dane pobrane z Modelu do postaci
string
wyświetlanej w debuggerze (i przez rozszerzenie do zwykłego pliku tekstowego). Jeśli mogę pobrać dane modelu i przetłumaczyć je swobodnie na tekst bez zmiany widoku lub modelu i tylko kontrolera, to jestem na dobrej drodze.To powiedziawszy, będziesz musiał mieć odniesienia między różnymi komponentami, aby wszystko działało. Kontroler musi wiedzieć o widoku, aby przesyłać dane, widok musi wiedzieć o kontrolerze, aby poinformować go, kiedy wprowadzono zmianę (na przykład, gdy użytkownik kliknie „Zapisz” lub „Nowy ...”). Kontroler musi wiedzieć o modelu, aby pobrać dane, ale argumentowałbym, że model nie powinien wiedzieć o niczym innym.
Zastrzeżenie: Pochodzę z całkowicie Mac, Objective-C, kakao, które naprawdę popycha cię do paradygmatu MVC, czy chcesz, czy nie.
źródło
Ogólnie rzecz biorąc, chcesz, aby Twój model zawierał wszystkie interakcje z tym modelem. Na przykład wszystkie działania CRUD (Utwórz, Odczytaj, Aktualizuj, Usuń) są częścią modelu. To samo dotyczy specjalnych obliczeń. Jest kilka dobrych powodów:
W kontrolerze (aplikacji MVC) wszystko, co robisz, to zbieranie modeli, których potrzebujesz w swoim widoku, i wywoływanie odpowiednich funkcji w modelu. Wszelkie zmiany stanu modelu mają miejsce w tej warstwie.
Twój Widok wyświetla po prostu przygotowane modele. Zasadniczo widok odczytuje tylko model i odpowiednio dostosowuje jego wynik.
Mapowanie ogólnej zasady do rzeczywistych klas
Pamiętaj, że twoje okna dialogowe są widokami. Jeśli masz już klasę okna dialogowego, nie ma powodu, aby tworzyć inną klasę „Widok”. Warstwa Presenter zasadniczo wiąże model z kontrolkami w Widoku. Logika biznesowa i wszystkie ważne dane są przechowywane w modelu.
źródło