Widok modelu View-Model został opracowany przez Microsoft w celu ukierunkowania platform programistycznych interfejsu użytkownika, które obsługują programowanie oparte na zdarzeniach, w szczególności Windows Presentation Foundation (WPF) i Silverlight na platformach .NET przy użyciu języków XAML i .NET. Przez lata wiele frameworków Javascript, takich jak Angular, Knockout i ExtJS, przyjęło ten wzorzec.
Podobnie jak większość wzorców oprogramowania, MVVM ma odpowiednie zastosowania i nadużycia. Na jakich warunkach właściwe jest stosowanie MVVM? Kiedy jest to niewskazane?
Odpowiedzi:
MVVM jest przeznaczony do stosowania tam, gdzie potrzebne są złożone interakcje użytkownika przy użyciu interfejsu użytkownika o wysokiej wierności (np. WPF ).
W przypadku interfejsów użytkownika, w których taka bogata interakcja nie jest potrzebna, MVVM może być przesadą; MVP może być bardziej naturalnym wyborem. W przypadku aplikacji internetowych lepiej pasuje MVC. W przypadku bardzo małych aplikacji, które nigdy nie będą się powiększać (takich jak małe narzędzia Winforms), wystarcza kodowanie.
źródło
Czasami MVVM może być pułapką. Z mojego doświadczenia wynika, że faworyzuje aplikacje typu CRUD (formularze zamiast danych) w porównaniu do bardziej zorientowanych na zadania interfejsów użytkownika. Nie twierdzę, że sugeruje to złą architekturę dla zaplecza / innych warstw w aplikacji, ale widziałem wiele aplikacji MVVM pochodzących z architekturą „DDD light”. Nie wiem, dlaczego dokładnie dlatego, że wiązanie jest tak łatwe i bardzo proste jest skonfigurowanie aplikacji za pomocą ORM i MVVM / Binding przy użyciu obiektów domeny POCO / Anemic.
źródło
MVVM jest pasmem pomocniczym dla źle zaprojektowanych warstw wiążących dane. W szczególności ma wiele zastosowań w świecie WPF / silverlight / WP7 z powodu ograniczeń w wiązaniu danych w WPF / XAML.
Odtąd zakładam, że mówimy o WPF / XAML, ponieważ to wyjaśni sprawę. Przyjrzyjmy się niektórym niedociągnięciom, które MVVM zamierza rozwiązać w WPF / XAML.
Kształt danych a kształt interfejsu użytkownika
„VM” w MVVM tworzy zestaw obiektów zdefiniowanych w C #, które odwzorowują na zestaw obiektów prezentacji zdefiniowanych w XAML. Te obiekty C # są zazwyczaj połączone z XAML za pośrednictwem właściwości DataContext na obiektach prezentacji.
W rezultacie wykres obiektu viewmodel musi zostać odwzorowany na wykresie obiektu prezentacji aplikacji. Nie oznacza to, że mapowanie musi być jeden do jednego, ale jeśli kontrolka listy jest zawarta w kontrolce okna, wówczas musi istnieć sposób na przejście z obiektu DataContext okna do obiektu, który opisuje dane tej listy.
Graf obiektowy viewmodel z powodzeniem oddziela wykres obiektowy modelu od grafu obiektowego interfejsu użytkownika, ale kosztem dodatkowej warstwy viewmodel, którą należy zbudować i utrzymywać.
Jeśli chcę przenieść niektóre dane z ekranu A na ekran B, muszę zadzierać z modelami viewmodels. Zdaniem biznesmena jest to zmiana interfejsu użytkownika. To powinno odbywać się wyłącznie w świecie XAML. Niestety rzadko. Co gorsza, w zależności od struktury modeli viewmode i tego, jak aktywnie zmieniają się dane, do wykonania tej zmiany może być konieczne przekierowanie danych.
Obejście nieefektywnego wiązania danych
Powiązania WPF / XAML są niewystarczająco ekspresyjne. Zasadniczo można uzyskać sposób dotarcia do obiektu, ścieżkę właściwości do przejścia i konwertery powiązań, aby dostosować wartość właściwości danych do wymagań obiektu prezentacji.
Jeśli musisz powiązać właściwość w języku C # z czymkolwiek bardziej złożonym, zasadniczo nie masz szczęścia. Nigdy nie widziałem aplikacji WPF bez konwertera powiązań, który zmieniłby true / false w Visible / Collapsed. Wiele aplikacji WPF ma również coś o nazwie NegatingVisibilityConverter lub podobny, który odwraca polaryzację. To powinno wywoływać dzwonki alarmowe.
MVVM zawiera wytyczne dotyczące strukturyzacji kodu C #, które można wykorzystać do złagodzenia tego ograniczenia. Możesz wystawić właściwość w swoim viewmodelu o nazwie SomeButtonVisibility i po prostu powiązać ją z widocznością tego przycisku. Twój XAML jest ładny i ładny teraz ... ale stałeś się urzędnikiem - teraz musisz ujawnić + aktualizację powiązań w dwóch miejscach (interfejs użytkownika i kod w języku C #), gdy twój interfejs ewoluuje. Jeśli potrzebujesz tego samego przycisku, aby znajdować się na innym ekranie, musisz udostępnić podobną właściwość w modelu widoku, do którego ten ekran może uzyskać dostęp. Co gorsza, nie mogę po prostu spojrzeć na XAML i zobaczyć, kiedy przycisk będzie już widoczny. Jak tylko powiązania staną się nieco nieistotne, muszę wykonać pracę detektywistyczną w kodzie C #.
Dostęp do danych jest agresywnie ograniczony
Ponieważ dane na ogół wchodzą do interfejsu użytkownika za pośrednictwem właściwości DataContext, trudno jest spójnie reprezentować dane globalne lub dane sesji w całej aplikacji.
Idea „aktualnie zalogowanego użytkownika” jest świetnym przykładem - często jest to naprawdę globalna sprawa w ramach jednej aplikacji. W WPF / XAML bardzo trudno jest zapewnić globalny dostęp do bieżącego użytkownika w spójny sposób.
Chciałbym swobodnie używać słowa „CurrentUser” w powiązaniach danych, aby odnosić się do aktualnie zalogowanego użytkownika. Zamiast tego muszę się upewnić, że każdy DataContext daje mi sposób na dotarcie do obiektu bieżącego użytkownika. MVVM może sobie z tym poradzić, ale modele widokowe będą bałaganem, ponieważ wszystkie muszą zapewniać dostęp do tych globalnych danych.
Przykład, w którym przewraca się MVVM
Powiedzmy, że mamy listę użytkowników. Obok każdego użytkownika chcemy wyświetlić przycisk „usuń użytkownika”, ale tylko wtedy, gdy zalogowanym użytkownikiem jest administrator. Ponadto użytkownicy nie mogą się usuwać.
Obiekty modelu nie powinny wiedzieć o aktualnie zalogowanym użytkowniku - będą po prostu reprezentować rekordy użytkownika w bazie danych, ale w jakiś sposób aktualnie zalogowany użytkownik musi być narażony na powiązania danych w wierszach listy. MVVM nakazuje utworzenie obiektu viewmodel dla każdego wiersza listy, który tworzy aktualnie zalogowanego użytkownika z użytkownikiem reprezentowanym przez ten wiersz listy, a następnie udostępnienie właściwości o nazwie „DeleteButtonVisibility” lub „CanDelete” na tym obiekcie viewmodel (w zależności od twoich odczuć o wiązaniu konwerterów).
Ten obiekt będzie wyglądał okropnie podobnie do obiektu użytkownika pod wieloma innymi względami - może być konieczne odzwierciedlenie wszystkich właściwości obiektu modelu użytkownika i przekazywanie aktualizacji tych danych w miarę jego zmian. Wydaje się to bardzo niegrzeczne - ponownie, MVVM czyni cię urzędnikiem, zmuszając cię do utrzymania tego obiektu podobnego do użytkownika.
Zastanów się - prawdopodobnie musisz również reprezentować właściwości użytkownika w bazie danych, modelu i widoku. Jeśli masz interfejs API między tobą a bazą danych, jest gorzej - są one reprezentowane w bazie danych, serwerze API, kliencie API, modelu i widoku. Byłbym bardzo niezdecydowany, aby przyjąć wzór projektowy, który dodał kolejną warstwę, którą należy dotknąć za każdym razem, gdy właściwość jest dodawana lub zmieniana.
Co gorsza, ta warstwa skaluje się ze złożonością interfejsu użytkownika, a nie ze złożonością modelu danych. Często te same dane są reprezentowane w wielu miejscach i w interfejsie użytkownika - to nie tylko dodaje warstwę, ale dodaje warstwę o dużej dodatkowej powierzchni!
Jak mogło być
W przypadku opisanym powyżej chciałbym powiedzieć:
CurrentUser będzie globalnie narażony na wszystkie XAML w mojej aplikacji. Id odwoływałby się do właściwości w DataContext dla mojego wiersza listy. Widoczność zmieni się automatycznie z logicznej. Wszelkie aktualizacje Id, CurrentUser.IsAdmin, CurrentUser lub CurrentUser.Id spowodowałyby aktualizację widoczności tego przycisku. Bułka z masłem.
Zamiast tego WPF / XAML zmusza użytkowników do stworzenia kompletnego bałaganu. O ile wiem, niektórzy kreatywni blogerzy podali nazwę temu bałaganowi, a ta nazwa to MVVM. Nie daj się zwieść - nie należy do tej samej klasy co wzorce projektowe GoF. To brzydki hack do obejścia brzydkiego systemu wiązania danych.
(Takie podejście jest czasem nazywane „programowaniem reaktywnym”, na wypadek, gdybyś chciał przeczytać więcej).
Podsumowując
Jeśli musisz pracować w WPF / XAML, nadal nie polecam MVVM.
Chcesz, aby Twój kod był tak skonstruowany, jak w powyższym przykładzie „jak mogło być”. Model byłby wystawiony bezpośrednio na widok, ze złożonymi wyrażeniami powiązania danych + elastycznymi koercjami wartości. Jest o wiele lepszy - bardziej czytelny, zapisywalny i łatwiejszy w utrzymaniu.
MVVM mówi, abyś ustrukturyzował swój kod w bardziej szczegółowy, mniej konserwowalny sposób.
Zamiast MVVM, stwórz kilka rzeczy, które pomogą ci przybliżyć dobre wrażenia: Opracuj konwencję konsekwentnego wyświetlania stanu globalnego w interfejsie użytkownika. Zbuduj sobie narzędzia z konwerterów wiązania, MultiBinding itp., Które pozwalają wyrazić bardziej złożone wyrażenia wiązania. Zbuduj sobie bibliotekę wiążących konwerterów, aby sprawić, że częste przypadki przymusu będą mniej bolesne.
Jeszcze lepiej - zamień XAML na coś bardziej wyrazistego. XAML to bardzo prosty format XML do tworzenia instancji obiektów C # - nie byłoby trudno wymyślić bardziej wyrazisty wariant.
Moje inne zalecenie: nie używaj zestawów narzędzi, które wymuszają tego rodzaju kompromisy. Zaszkodzą jakości twojego produktu końcowego, popychając cię do bzdur jak MVVM, zamiast skupiać się na domenie problemowej.
źródło
Bardzo lubię MVVM i uważam, że jej wyzwania są motywujące i widzę wiele korzyści, ale ...
W przypadku aplikacji lub gier, które wymagają dużej ilości interfejsu użytkownika / kodu interakcji, aby dodać wiele niestandardowych zachowań przy jednoczesnym utrzymaniu doskonałości - często lepiej jest użyć nieco brudnego MVVM - używaj go, gdy jest użyteczny lub bardziej skoncentrowany na danych, w przeciwieństwie do interakcyjne obszary kodu. Powiedz, że chcesz utworzyć formant i przenosić go między różnymi kontrolkami nadrzędnymi lub w inny sposób buforować ...
Ma dość stromą krzywą uczenia się, więc jeśli nie masz czasu, planujesz dużo rozwinąć w WPF / SL, masz projektantów wykwalifikowanych w Blend, czujesz potrzebę napisania kodu testowego dla twojego interfejsu użytkownika lub w inny sposób oczekujesz lat konserwacji dla twojego projekt - może się nie opłacić.
Niewielu projektantów zna Blend, nie wszystkie projekty warto skoncentrować na automatycznych testach na warstwie prezentacji, ponieważ i tak trzeba to przetestować ręcznie i tak znajdziesz najważniejsze błędy, a nie przez testowanie maszyn wirtualnych.
To naprawdę inwestycja. Najpierw musisz zapoznać się z podstawami WPF / SL i XAML, a następnie dowiedzieć się, jak poprawnie wykonać powiązania, połączyć się z vms w pewnej kolejności, uzyskać właściwe dowodzenie, wybrać szkielet w większości przypadków, które mogłyby być problematycznym z powodu licencjonowania, zbuduj bibliotekę sippetów, aby efektywnie kodować, tylko po to, aby przekonać się, że platforma nie zawsze działa dobrze z powiązaniami i musisz zbudować bibliotekę zachowań, które zapewnią ci to, czego potrzebujesz.
Ogólnie rzecz biorąc - jeśli pokonasz wszystkie przeszkody i staniesz się dość biegły w tym schemacie - wszystko to zwróci się w jasności, łatwości konserwacji i ... chwaleniu się prawami? :)
źródło
Od lat jestem programistą WPF / Silverlight, budując ogromne aplikacje, takie jak systemy transakcyjne, na MVVM.
Z biegiem lat nauczyłem się, że ścisłe MVVM zjada czas i kosztuje. Przez ścisłe rozumiem zasady takie jak „bez kodu”.
W niczym innym, jak w najbardziej podstawowej aplikacji do tworzenia formularzy / baz danych, nie jest możliwe, aby nie mieć kodu.
Twój projektant określi w pierwszym dniu coś, co nie jest możliwe ze standardowymi kontrolkami, więc musisz zbudować serię niestandardowych kontrolek lub zawinąć istniejące kontrolki, aby wspierać paradygmat interakcji podczas pracy z MVVM.
Napisałem wszelkiego rodzaju eleganckie interfejsy użytkownika za pomocą matematyki, bezwładności, gestów itp. I ich ciężkiej pracy.
Ale to wszystko kryje się za kodem, po prostu tego nie widać. Musisz obsługiwać kliknięcia przycisków, przewijanie, przeciąganie itp., Ale wszystko jest ładnie zamknięte w zestawie elementów sterujących, co w jakiś sposób sprawia, że kod jest w porządku.
Często łatwiej jest po prostu napisać ukryty i sprytny interfejs użytkownika w widoku, zamiast budować zestaw elementów sterujących tylko ze względu na to.
Celem MVVM jest oddzielenie logiki aplikacji / biznesu od logiki interfejsu użytkownika. System wiązania i MVVM to dobry sposób na zrobienie tego.
Inne reklamowane cele, takie jak projektant XAML na jednym biurku, programista C # na drugim, jeden pracujący w Blenduj drugi w VS, jest błędem.
Kolejnym błędem jest możliwość szybkiego przeprojektowania interfejsu użytkownika. To się nigdy nie zdarza, jego przedwczesna optymalizacja; każda poważna przeróbka wymaga dużo pracy przy modelach widoku. Ulepszanie to jedno, ale szybkie przeglądy interfejsu użytkownika nie są możliwe; modele widoku muszą pasować do paradygmatu interakcji, więc sprzężenie jest ciaśniejsze, niż możesz sobie wyobrazić.
Dla mnie używam MVVM do oddzielenia logiki aplikacji (zwykle używam testowalnego kontrolera i zestawu modeli logiki bez logiki), ale niezależnie od kodu i sztuczek potrzebnych, aby mój interfejs wyglądał i działał w seksowny sposób, nie robię tego pocić się.
W przeciwnym razie skończysz w swoich projektach, fajnych animacjach itp. Tylko dlatego, że pomysł, jak to zrobić MVVM, staje się zbyt zadziwiający.
MVVM, podobnie jak większość rzeczy w życiu, ma słodki punkt pomiędzy dwoma skrajnościami.
Najważniejszą rzeczą w projektowaniu oprogramowania jest wczesne dostarczenie produktu, sprawdzenie, jakie funkcje są używane, interfejs użytkownika działa dobrze, a nie pisanie pięknego kodu dla produktu, którego nikt nie używa.
źródło
Jeśli twoja aplikacja wymaga powiązania z nadmierną ilością danych w czasie rzeczywistym, MVVM może faktycznie przeszkodzić, ponieważ wprowadza abstrakcje, które spowalniają proces i, zakładając, że mówimy teraz o WPF / Silverlight / WP7, wiązanie silnik nie jest obecnie tak wydajny; chociaż udoskonalenia są już w drodze.
W obecnej postaci MVVM nie jest jedyną częścią równania, którą należy wziąć pod uwagę. Pure MVVM musi być obsługiwany przez infrastrukturę taką jak wzorzec Mediator, aby umożliwić komunikację przez rozłączone ViewModels.
Pomimo opinii blucza powyżej, MVVM jest zgodny z wzorcami GoF. Jeśli przyjrzysz się wzorom, MVVM jest odpowiednikiem wzorca Pasywnego prezentera widoku modelu, który pojawił się mniej więcej w tym samym czasie co MVVM. Często będziesz tu narzekać na złożoność MVVM wyłącznie dlatego, że nie rozumieją, jak zaprojektować go przy użyciu.
Innym obszarem, w którym znalazłem problemy z MVVM, jest potrzeba zastosowania technologii strony trzeciej, która nie jest zaprojektowana do jej obsługi (takiej jak struktura UII dla MS Dynamics). Czasami musisz zadać sobie pytanie, czy warto pracować z MVVM po prostu hakując inne technologie.
Jeśli miksujesz i dopasowujesz coś takiego jak Win Forms do swojego rozwiązania WPF, wtedy ta część rozwiązania prawdopodobnie nie będzie również odpowiednia dla MVVM. Mam nadzieję, że daje to pewne wyobrażenie o niektórych obszarach, w których MVVM nie ma zastosowania.
źródło
Korzystanie z MVVM nie ma sensu, gdy:
Otóż to. Naprawdę nie mogę wymyślić, dlaczego NIE używałbyś MVVM podczas pracy z WPF / Silverlight, chyba że testujesz lub debugujesz coś w oddzielnym projekcie. Uważam, że wzór projektowania jest idealny do rozwoju WPF / Silverlight ze względu na sposób działania powiązań XAML.
Chodzi o to, że cała MVVM jest uruchomiona w twoich ViewModels, a Twoje Widoki są po prostu ładną warstwą, z której użytkownicy mogą korzystać w celu interakcji z Twoimi ViewModels. Chcesz kliknąć przycisk, w rzeczywistości korzystasz z metody ViewModel. Chcesz zmienić stronę, w rzeczywistości zmieniasz właściwość CurrentPage w ViewModel.
Używam MVVM do wszystkich prac rozwojowych WPF / Silverlight, nawet małych, prostych projektów jednostronicowych, chociaż sposób, w jaki korzystam z MVVM, jest różny w zależności od wielkości projektu i tego, czego potrzebuję. Za jednym razem, gdy zrobiłem małą aplikację bez MVVM, skończyło się na tym, że jej żałuję (później została zrefaktoryzowana do używania MVVM podczas dodawania aktualizacji)
źródło
Pracowałem dla klienta nad projektem, który był opóźniony w kodzie, próbując przekonwertować MVVM i był to wielki bałagan. Nie oznacza to, że wszystkie projekty za kodem to bałagan. Widoki spowodowałyby błąd lub awarię Blend, co spowodowało problemy dla projektantów.
Zajmowałem się RoR i prawie zrezygnowałem z robienia czegokolwiek z formularzami internetowymi ASP.NET, ale kiedy pojawiło się ASP.NET MVC, starałem się nauczyć jak najwięcej, często korzystając z książek ASP.NET MVC In Action i serwera kodeków jako odniesienia . Chociaż jest to inny wzorzec, wykorzystuję wiele rzeczy, których nauczyłem się z książek In Action w rozwoju SL / MVVM.
Kiedy zacząłem pracować z Silverlight, byłem zaskoczony, jak nagi był i wydawało mi się, że muszę wybrać jedną z wielu dostępnych ram, aby ją ubrać. Widzę to jako problem, gdy ludzie rezygnują z nauki MVVM.
Zacząłem od doskonałego MVVM-Light, które pomogło mi uzyskać sprzedany chwyt tego wzoru. Później zacząłem pracować z Caliburn Micro, a potem zapaliły się światła. Dla mnie Caliburn Micro jest jak używanie ASP.NET MVC zamiast ASP.NET Webforms. Tak więc nawet w przypadku małych przykładowych aplikacji tworzę projekt NuGet CM i jestem wyłączony. Postępuję zgodnie z pierwszym podejściem ViewModel, a moje widoki są głupie i łatwe w obsłudze w Blend. Moje maszyny wirtualne są testowalne, jeśli jesteś w to zaangażowany, a dzięki CM można dość łatwo przewijać złożone układy ekranu.
źródło
Sprawdź tę alternatywę. Ta opcja omija sposób wiązania danych WPF, szablonów danych i MVVM. Ta opcja jest bardziej podobna do starego, prostego i niezawodnego podejścia designer.cs do WinForm.
Kompozyty WPF
http://wpfcomposites.codeplex.com/
Tutaj zwięzły kod C # dla WPF jest wytwarzany przez nałożenie prostej matrycy na interfejs użytkownika za pomocą kompozytów opartych na siatce. Jeśli nowoczesny interfejs użytkownika XAML zawiera tylko kilka etykiet tekstowych i listę zdjęć, dlaczego nie można tego zdefiniować za pomocą prostej linii kodu: grid.AddText (guid, współrzędna x, współrzędna y)? Zauważ, że nie jest to na płótnie, ale wciąż w kontenerach WPF: grid, dockpanel itp. WPF jest niezwykle potężny. To podejście jedynie to wykorzystuje.
Deweloperzy zazwyczaj nie mają nic przeciwko matrycom i indeksom. Zacznij od poziomu pojemnika gruboziarnistego zdefiniowanego przez GUID obiektów do przesyłania danych (DTO) lub POCO, a następnie uzupełnij te kluczowane pojemniki drobniejszą ziarnistą macierzą potencjalnych wierszy i kolumn?
Powyższy projekt codeplex wprowadza to podejście, zaczynając od kontrolki ListBox, ale rozszerza się, aby objąć wszystkie kontrolki kompozytowe WPF. Na przykład każdy element listy jest złożonym dodatkiem z identyfikatorem GUID (kompozyt wiąże jeden do jednego z klasą), a następnie wewnątrz tego elementu znajduje się siatka, na której elementy potomne interfejsu użytkownika (dzieci wiążą jeden do jednego z właściwościami w klasie) można dodawać do woli za pomocą kodu. Dzieci mogą być blokami tekstowymi lub obrazami.
Chodzi o to, aby wykorzystać indeksy i dobrze zdefiniowaną strukturę elementu interfejsu użytkownika (wymusza zastosowanie ListBox o tematyce PresentationFramework.Aero jako podstawy) zamiast szablonów danych. To nowe podejście celowo ogranicza to, co można zrobić, ale w ten sposób daje zwięzły, solidny kod C #, który jest intuicyjny. Nie ma potrzeby szukania rozwiązań szablonów kontrolnych do stylizowania paska przewijania lub zaśmiecania rozwiązania wieloma szablonami danych do prostych zadań.
źródło
MVVM opiera się głównie na frameworku interfejsu użytkownika, którego używam. Tak więc z czymś takim jak WPF lub Silverlight, który ma paradygmat oparty na wiązaniu z tekstem danych, ten tekst danych można zawsze nazwać modelem widoku.
Pytanie więc brzmi: kiedy budujesz dużą, oddzielną klasę, która jest modelem widoku dla tej kontrolki / okna / aplikacji i kiedy możesz uciec od używania już zbudowanych obiektów.
Mamy więc klasyczne pytanie o dodanie warstwy abstrakcji. maszyna wirtualna doda wagę, bezwładność i strukturę do projektu. Ułatwi to rozbudowę, ale będzie trudniejsze do zmiany i dłuższe do zbudowania. Żadna z tych rzeczy nie jest łatwa do zmierzenia.
Aby uzyskać tanią odpowiedź, MVVM nie jest odpowiedni dla aplikacji wiersza polecenia lub usług sieciowych :)
źródło