W przeszłości korzystałem z MVP i MVC i wolę MVP, ponieważ moim zdaniem znacznie lepiej kontroluje przebieg wykonywania.
Stworzyłem swoją infrastrukturę (klasy magazynu danych / repozytorium) i używam ich bez problemu podczas twardego kodowania przykładowych danych, więc teraz przechodzę do GUI i przygotowuję MVP.
Sekcja A
Widziałem MVP używającego widoku jako punktu wejścia, to znaczy w metodzie konstruktora widoków tworzy on prezentera, który z kolei tworzy model, łącząc zdarzenia w razie potrzeby.
Widziałem również prezentera jako punkt wejściowy, w którym tworzony jest widok, model i prezenter. Następnie ten prezenter otrzymuje widok i model obiektu w swoim konstruktorze w celu połączenia zdarzeń.
Jak w 2, ale model nie jest przekazywany do prezentera. Zamiast tego model jest statyczną klasą, w której wywoływane są metody, a odpowiedzi zwracane bezpośrednio.
Sekcja B
Widziałem, jeśli chodzi o synchronizację widoku i modelu.
Ilekroć zmienia się wartość w widoku, tj.
TextChanged
Zdarzenie w .Net / C #. To uruchamia model,DataChangedEvent
który jest przekazywany do modelu, aby cały czas był zsynchronizowany. A gdy model się zmienia, tj. Zdarzenie w tle, którego słucha, widok jest aktualizowany za pomocą tego samego pomysłu wywołania aDataChangedEvent
. Gdy użytkownik chce zatwierdzić zmianySaveEvent
, uruchamia się, przechodząc do modelu, aby zapisać. W takim przypadku model naśladuje dane widoku i przetwarza działania.Podobne do # b1, jednak widok nie jest zsynchronizowany z modelem przez cały czas. Zamiast tego, gdy użytkownik chce zatwierdzić zmiany,
SaveEvent
zostaje zwolniony, a prezenter pobiera najnowsze szczegóły i przekazuje je do modelu. w tym przypadku model nie wie o danych widoków, dopóki nie będzie musiał na nim działać, w którym to przypadku zostaną przekazane wszystkie potrzebne szczegóły.
Sekcja C
Wyświetlanie obiektów biznesowych w widoku, tj. Obiektu (MyClass), a nie pierwotnych danych (int, double)
Widok ma pola właściwości dla wszystkich swoich danych, które będą wyświetlane jako obiekty domeny / biznesu. Na przykład
view.Animals
ujawniaIEnumerable<IAnimal>
właściwość, nawet jeśli widok przetwarza je na węzły w TreeView. Następnie dla wybranego zwierzęcia odsłoniłby sięSelectedAnimal
jakoIAnimal
własność.Widok nie ma wiedzy o obiektach domeny, udostępnia właściwości tylko dla typów obiektów zawartych w elementach pierwotnych / ramowych (.Net / Java). W tym przypadku prezenter przekazuje obiekt adaptera obiekt domeny, adapter następnie przetłumaczy dany obiekt biznesowy na formanty widoczne w widoku. W tym przypadku adapter musi mieć dostęp do rzeczywistych elementów sterujących w widoku, a nie tylko do dowolnego widoku, dlatego zostaje ściślej sprzężony.
Sekcja D
Wiele widoków użytych do utworzenia jednego elementu sterującego. tzn. masz złożony widok z prostym modelem, takim jak zapisywanie obiektów różnych typów. Możesz mieć system menu z boku przy każdym kliknięciu elementu, wyświetlane są odpowiednie elementy sterujące.
Tworzysz jeden ogromny widok, który zawiera wszystkie poszczególne elementy sterujące, które są widoczne przez interfejs widoków.
Masz kilka widoków. Masz jeden widok na menu i pusty panel. Ten widok tworzy inne wymagane widoki, ale ich nie wyświetla (widoczny = fałsz), ten widok implementuje również interfejs dla każdego widoku, który zawiera (tj. Widoki potomne), dzięki czemu może być udostępniany jednemu prezenterowi. Pusty panel jest wypełniony innymi widokami (
Controls.Add(myview)
) i ((myview.visible = true
). Zdarzenia wywołane w tych „podrzędnych” widokach są obsługiwane przez widok nadrzędny, który z kolei przekazuje zdarzenie prezenterowi i odwrotnie w celu dostarczenia zdarzeń z powrotem do elementów potomnych.Każdy widok, niezależnie od tego, czy jest to główny widok rodzica, czy mniejszy widok dziecka, jest połączony z własnym prezenterem i modelem. Możesz dosłownie po prostu upuścić kontrolkę widoku do istniejącej postaci, a ona będzie mieć gotową funkcjonalność, wystarczy podłączyć do prezentera za kulisami.
Sekcja E
Jeśli wszystko ma interfejs, teraz oparte na sposobie wykonania MVP w powyższych przykładach wpłynie na tę odpowiedź, ponieważ mogą one nie być kompatybilne krzyżowo.
Wszystko ma interfejs, widok, prezentera i model. Każdy z nich ma oczywiście konkretne wdrożenie. Nawet jeśli masz tylko jeden konkretny widok, model i prezentera.
Widok i model mają interfejs. Dzięki temu widoki i modele mogą się różnić. Prezenter tworzy / otrzymuje widok i modeluje obiekty i służy tylko do przekazywania komunikatów między nimi.
Tylko widok ma interfejs. Model ma metody statyczne i nie jest tworzony, dlatego nie ma potrzeby używania interfejsu. Jeśli chcesz mieć inny model, prezenter wywołuje inny zestaw metod klasy statycznej. Będąc statycznym Model nie ma linku do prezentera.
Osobiste myśli
Ze wszystkich przedstawionych przeze mnie wariantów (większość, których prawdopodobnie użyłem w jakiejś formie), których jestem pewien, że jest ich więcej. Wolę A3 jako logikę biznesową wielokrotnego użytku poza MVP, B2 dla mniejszego powielania danych i mniejszej liczby zdarzeń. C1 za brak dodawania w innej klasie, na pewno umieszcza w widoku niewielką ilość logiki, która nie może być testowana jednostkowo (sposób wizualizacji obiektu domeny), ale można to sprawdzić w kodzie lub po prostu wyświetlić w aplikacji. Gdyby logika była złożona, zgodziłbym się na klasę adaptera, ale nie we wszystkich przypadkach. W przypadku sekcji D wydaje mi się, że D1 tworzy widok, który jest zbyt duży przynajmniej na przykład w menu. Używałem wcześniej D2 i D3. Problem z D2 polega na tym, że w końcu musisz napisać dużo kodu, aby przekierować zdarzenia do i z prezentera do właściwego widoku potomnego i nie jest on zgodny z funkcją przeciągnij / upuść, każdy nowy element sterujący wymaga dodatkowego okablowania, aby obsługiwać jednego prezentera. D3 jest moim preferowanym wyborem, ale dodaje jeszcze więcej klas jako prezenterów i modeli do obsługi widoku, nawet jeśli widok jest bardzo prosty lub nie trzeba go ponownie wykorzystywać. myślę, że mieszanka D2 i D3 najlepiej opiera się na okolicznościach. Jeśli chodzi o sekcję E, myślę, że wszystko, co ma interfejs, może być przesadzone. Już to robię dla obiektów domenowych / biznesowych i często nie widzę w tym „przewagi”, ale pomaga to w wyśmiewaniu obiektów w testach. Osobiście widziałbym E2 jako klasyczne rozwiązanie, chociaż widziałem E3 zastosowane w 2 projektach, nad którymi wcześniej pracowałem. myślę, że mieszanka D2 i D3 najlepiej opiera się na okolicznościach. Jeśli chodzi o sekcję E, myślę, że wszystko, co ma interfejs, może być przesadą. Już to robię dla obiektów domenowych / biznesowych i często nie widzę w tym „przewagi”, ale pomaga to w wyśmiewaniu obiektów w testach. Osobiście widziałbym E2 jako klasyczne rozwiązanie, chociaż widziałem E3 zastosowane w 2 projektach, nad którymi wcześniej pracowałem. myślę, że mieszanka D2 i D3 najlepiej opiera się na okolicznościach. Jeśli chodzi o sekcję E, myślę, że wszystko, co ma interfejs, może być przesadzone. Już to robię dla obiektów domenowych / biznesowych i często nie widzę żadnej korzyści w „projektowaniu”, ale pomaga to w wyśmiewaniu obiektów w testach. Osobiście widziałbym E2 jako klasyczne rozwiązanie, chociaż widziałem E3 zastosowane w 2 projektach, nad którymi wcześniej pracowałem.
Pytanie
Czy poprawnie wdrażam MVP? Czy istnieje odpowiedni sposób, aby to zrobić?
Przeczytałem pracę Martina Fowlera, która ma różne wersje, i pamiętam, kiedy po raz pierwszy zacząłem tworzyć MVC, zrozumiałem koncepcję, ale początkowo nie mogłem ustalić, gdzie jest punkt wejścia, wszystko ma swoją funkcję, ale to, co kontroluje i tworzy oryginał zestaw obiektów MVC.
źródło
Odpowiedzi:
Wiele z tego, co tu prezentujesz, jest bardzo rozsądne i solidne. Niektóre wybory będą zależeć od specyfiki aplikacji i tego, który „wydaje się” odpowiedni. Jak zwykle przez większość czasu, nie będzie jednej właściwej odpowiedzi. Niektóre z tych wyborów będą miały sens tutaj i mogą być całkowicie niewłaściwe dla następnej aplikacji i okoliczności. Nie znając niektórych szczegółów aplikacji, myślę, że jesteś na dobrej drodze i podjąłeś rozsądne, przemyślane decyzje.
Uważam, że Prezenter prawie zawsze powinien być punktem wyjścia. Posiadanie interfejsu użytkownika jako punktu wejścia powoduje, że interfejs użytkownika jest zbyt logiczny i odbiera możliwość zastąpienia nowego interfejsu użytkownika bez dużych zmian w kodowaniu. I tak naprawdę jest to praca prezentera.
źródło
W naszej aplikacji WinForm .NET 2.0 używamy zmodyfikowanej formy MVP. Dwa elementy, których nam brakowało, to zmodyfikowany adapter WPF ViewModel i dodanie powiązania danych. Naszym specyficznym wzorem jest MVPVM.
Niemal w każdym przypadku podłączamy się jako prezenter, z wyjątkiem niestandardowych elementów sterowania użytkownika, które są okablowane jako pierwsze dla wygody projektanta. Używamy wstrzykiwania zależności, generowanych kodów ViewModels, BDD dla prezenterów i TDD / TED dla modelu.
Maszyny wirtualne są po prostu masywnym, płaskim zwitkiem właściwości, które podnoszą PropertyChanged po ich zmianie. Bardzo łatwo było je wygenerować za pomocą kodu (i powiązanych testów jednostkowych ćwiczeń). Używamy ich do odczytywania i zapisywania w kontrolach interaktywnych przez użytkownika oraz do kontrolowania statusów włączonych. ViewModel jest połączony z View, ponieważ używamy wiązania danych do cholernie blisko wszystkiego innego.
Widok będzie czasem zawierał metody umożliwiające osiągnięcie rzeczy, których maszyna wirtualna nie może. Zwykle kontroluje to widoczność przedmiotów (WinForm może być wybredny) i rzeczy, które nie chcą być danymi. Widok zawsze ujawnia zdarzenia takie jak „Logowanie” lub „Uruchom ponownie”, z odpowiednimi EventArgs do działania na zachowaniach użytkowników. O ile nie musieliśmy używać hacka typu „View.ShowLoginBox”, widok jest całkowicie wymienny, o ile spełnia ogólne wymagania projektowe.
Wzięcie tego wzoru zajęło nam około 6-8 miesięcy. Ma wiele elementów, ale jest bardzo elastyczny i niezwykle wydajny. Nasza konkretna implementacja jest bardzo asynchroniczna i sterowana zdarzeniami, co może być jedynie artefaktem innych wymagań, a nie efektem ubocznym zachowania projektowego. Na przykład dodałem synchronizację wątków do klasy podstawowej, z której dziedziczy nasza maszyna wirtualna (która po prostu ujawniła metodę OnPropertyChanged w celu wywołania zdarzenia) - i poof, teraz możemy mieć wielowątkowe prezentery i modele.
źródło
Korzystam z wersji PureMvc, która została zmodyfikowana dla .Net, a następnie rozszerzona przeze mnie.
Przyzwyczaiłem się do PureMvc z używania go w aplikacjach Flex. Jest to szkielet typu gołe kości, więc można go łatwo dostosować, jeśli chcesz go dostosować.
Zabrałem ze sobą następujące swobody:
W PureMvc można użyć polecenia jako punktu wejścia, typowe polecenie Start skonfiguruje Model w takim zakresie, w jakim będzie to możliwe, a następnie utworzy formularz główny, utworzy i zarejestruje mediator dla tego formularza, a następnie wykona aplikację. Na formularzu.
Mediator formularza byłby odpowiedzialny za ustanowienie wszystkich sub-mediatorów, niektóre z nich można zautomatyzować ponownie za pomocą sztuczek refleksyjnych.
System, którego używam, jest zgodny z metodą przeciągnij / upuść, jeśli rozumiem twoje znaczenie. Rzeczywista forma jest tworzona w VS, ale moje doświadczenie dotyczy tylko formularzy, które mają statycznie utworzone formanty. Rzeczy takie jak dynamicznie tworzone pozycje menu wydają się wykonalne przy odrobinie ulepszenia mediatora dla tego menu lub podmenu. Owłosienie byłoby wtedy, gdy mediator nie miał statycznego elementu głównego, który mógłby zostać zaczepiony, a ty zacząłeś tworzyć dynamiczne mediatory „instancji”.
źródło