Jestem programistą C ++, który do tej pory używa wzorca MVC do projektowania GUI.
Ostatnio chciałem wrócić do C # i skonfigurowałem aplikację Windows Forms, ale teraz trochę się zagubiłem, jak przenieść ją do struktury zgodnej z MVC.
Obecnie próbuję „zadeklarować” klasę, którą otrzymałem dla WinForm jako Widok, i dodać klasę dla Modelu i Kontrolera w tle. Nie jestem jednak pewien, jak wchodzić w interakcje ze zdarzeniami, takimi jak kliknięcie przycisku. Zwykle przekierowuję te zdarzenia do kontrolera i wykonuję akcję w widoku po zakończeniu.
W tej konstelacji wydaje się to jednak niezadowalające. Na przykład, jeśli chcę zaimplementować przycisk „Wyjdź”, musiałbym przekierować zdarzenie z widoku do kontrolera, a także zaimplementować dodatkową metodę publiczną w moim widoku, którą można wywołać z kontrolera, podczas gdy ja może po prostu wywołać Close () z widoku w pierwszej instancji.
Czy masz dla mnie jakąś radę? Czy moje rozumienie formularzy Windows Forms w języku C # nie jest jeszcze wystarczająco dobre, aby wypróbować implementację MVC? Czy źle przypisuję klasie formularzy? Czy MVC jest po prostu nieodpowiednią architekturą dla tego przypadku użycia?
Odpowiedzi:
Przypadkowo pracuję nad projektem WinForms wzorowanym na MVC. Nie nazwałbym tego idealną odpowiedzią, ale wyjaśnię mój ogólny projekt i mam nadzieję, że pomoże ci to wymyślić własny.
Na podstawie lektury, którą zrobiłem przed rozpoczęciem tego projektu, wydaje się, że nie ma „właściwego” sposobu na wdrożenie tego. Postępowałem zgodnie z prostymi zasadami projektowania OOP i MVC, a reszta była próbą i błędem podczas opracowywania przepływu pracy.
Nie .. W twoim pytaniu nie ma wystarczającego kontekstu, aby udzielić bezpośredniej odpowiedzi na to pytanie. Dlaczego w ogóle korzystasz z MVC? Jakie są niefunkcjonalne wymagania twojego projektu? Czy twój projekt będzie bardzo obciążony interfejsem użytkownika? Czy zależy Ci bardziej na bezpieczeństwie i wolisz architekturę warstwową? Jakie są główne elementy twojego projektu? Być może każdy element wymaga innego wzorca projektowego. Dowiedz się, dlaczego chcesz skorzystać z tego wzorca projektowego, a możesz odpowiedzieć na własne pytanie;)
Moim powodem użycia MVC: jest to dość prosty wzorzec projektowy, który moim zdaniem należy zrozumieć, a mój projekt opiera się w dużej mierze na interakcji z użytkownikiem. Sposób, w jaki MVC pozwala programistom na rozwiązywanie problemów, jest wystarczający również dla mojej aplikacji. To sprawia, że mój kod dużo bardziej linkujących i sprawdzalne.
Przypuszczam również, że używam bardziej hybrydowego projektu. Zwykle idealna koncepcja przedstawiona w inżynierii oprogramowania nie sprawdza się w praktyce. Możesz zmodyfikować projekt, aby dostosować go do potrzeb twojego projektu. Nie musisz dać się wciągnąć w to, co jest dobre, a co złe. Istnieją ogólne praktyki, ale zasady mogą być zawsze zgięte lub złamane, o ile nie postrzelisz się w stopę.
Moje wdrożenie rozpoczęło się od projektu na wysokim poziomie, który dał mi pojęcie o tym, jakich komponentów będę potrzebować. Najlepiej zacząć w ten sposób i posuwać się w dół po architekturze. Oto schemat pakietu dla projektu (utworzonego w StarUML):
Zwróć uwagę, że każda warstwa oprócz warstwy prezentacji zależy od systemu przesyłania wiadomości. Jest to wspólny „język” wykorzystywany przez dolne warstwy i podsystemy tych warstw do komunikowania się ze sobą. W moim przypadku było to proste wyliczenie oparte na operacjach, które można wykonać. Co prowadzi mnie do następnego punktu ...
Pomyśl o operacjach lub poleceniach jako podstawie do wdrożenia. Co chcesz zrobić z aplikacją? Podziel go na najbardziej podstawowe operacje. Na przykład: CreateProject, WriteNotes, SaveProject, LoadProject itp. W GUI (lub klasach Form) wystąpi pewne zdarzenie (np. Naciśnięcie przycisku). Każda operacja ma powiązaną z nią metodę kontrolera. W tym przypadku coś takiego jak Wyjście jest zbyt proste. Aplikację można po prostu zamknąć z klasy Form. Ale załóżmy, że najpierw chciałem zachować niektóre dane aplikacji w pliku? Wywołam metodę „Zapisz” z odpowiedniej klasy kontrolera w ramach mojej metody naciskania przycisków.
Stamtąd kontroler wywoła prawidłowy zestaw operacji z klas usług. Klasy usług w mojej aplikacji działają jako interfejs do warstwy domeny. Sprawdzą poprawność danych wejściowych otrzymanych z wywołania metody kontrolera (a tym samym z GUI) i manipulują modelem danych.
Po zakończeniu sprawdzania poprawności i odpowiedniej manipulacji obiektem metoda usługi zwróci kod komunikatu do kontrolera. Na przykład
MessageCodes.SaveSuccess
. Zarówno kontroler, jak i klasy usług były oparte na obiektach domeny i / lub ogólnym zestawie operacji, które można grupować razem.Na przykład:
FileMenuController
(operacje: NewProject, SaveProject, LoadProject) ->ProjectServices
(CreateProject, PersistProjectToFile, LoadProjectFromFile). GdzieProject
byłaby klasa domeny w twoim modelu danych. Klasy kontrolera i usługi w moim przypadku były klasami, które nie nadają się do utworzenia z metodami statycznymi.Następnie sterownik rozpoznaje operację jako zakończoną niepowodzeniem / pomyślnie. Teraz kontroler ma własny system przesyłania wiadomości, którego używa do interakcji z warstwą prezentacji, stąd podwójna zależność między warstwą usługi a warstwą prezentacji. W takim przypadku klasa wywoływana
ViewState
wViewModels
pakiecie jest zawsze zwracana do GUI przez kontroler. Ten stan zawiera takie informacje, jak: „ czy stan, w którym próbujesz ustawić poprawną aplikację? ”, „ Czytelny dla człowieka komunikat o operacji, którą próbujesz wykonać i dlaczego zakończyła się ona niepowodzeniem (komunikaty o błędach) ” orazViewModel
klasa.ViewModel
Klasa zawiera odpowiednie dane z warstwy domeny GUI będzie użyć do aktualizacji widoku. Te modele widoków wyglądają jak klasy domenowe, ale w moim przypadku użyłem bardzo chudych obiektów. Zasadniczo nie zachowują się właściwie, po prostu przekazują informacje o stanie niższego poziomu aplikacji. Innymi słowy, NIGDY nie zamierzam oddawać moich klas domen do warstwy prezentacji. Z tego też powodu pakietyControllers
iServices
dzielą warstwę usługową na dwie części. Kontrolery nigdy nie będą obsługiwać klas domen ani sprawdzać ich stanu. Działają one po prostu jako granica przekształcająca dane istotne z GUI w dane istotne dla domeny, z których mogą korzystać usługi i odwrotnie. Włączenie logiki serwisowej do sterownika doprowadziłoby do bardzo grubego kontrolery, które są trudniejsze w utrzymaniu.Mam nadzieję, że daje to punkt wyjścia.
źródło