Po co umieszczać logikę biznesową w modelu? Co się stanie, gdy mam wiele rodzajów pamięci?

70

Zawsze myślałem, że logika biznesowa musi znajdować się w kontrolerze i że kontroler, ponieważ jest to „środkowa” część, pozostaje statyczna i że model / widok muszą być kapsułkowane za pomocą interfejsów. W ten sposób można zmienić logikę biznesową, nie wpływając na nic innego, zaprogramować wiele modeli (jeden dla każdej bazy danych / typu pamięci) i dziesiątki widoków (na przykład dla różnych platform).

Teraz czytam w tym pytaniu , że zawsze powinieneś umieszczać logikę biznesową w modelu i że kontroler jest głęboko związany z widokiem.

Dla mnie to naprawdę nie ma sensu i implikuje, że za każdym razem, gdy chcę mieć środki do obsługi innej bazy danych / rodzaju pamięci, muszę przepisać cały mój model, w tym logikę biznesową.

A jeśli chcę innego widoku, muszę przepisać zarówno widok, jak i kontroler.

Czy ktoś może wyjaśnić, dlaczego tak się dzieje, czy gdzieś się pomyliłem?

Steffen Winkler
źródło

Odpowiedzi:

69

Odpowiedź ElYusubova przebija ją, logika domeny powinna przejść do modelu, a logika aplikacji do kontrolera.

Dwa wyjaśnienia:

  • Pojęcie logiki biznesowej jest tutaj raczej bezużyteczne, ponieważ jest dwuznaczne. Logika biznesowa to ogólny termin na całą logikę, na której zależy przedsiębiorcom, oddzielający ją od zwykłych szczegółów technicznych, takich jak przechowywanie rzeczy w bazie danych lub renderowanie na ekranie. Zarówno logika domeny („prawidłowy adres e-mail wygląda jak ...”), jak i przepływy pracy / procesy biznesowe („gdy użytkownik się zarejestruje, poproś o swój adres e-mail”) są uważane za logikę biznesową, przy czym ta pierwsza wyraźnie należy do model, a ta ostatnia jest logiką aplikacji, która przechodzi do kontrolera.
  • MVC to wzór do umieszczania rzeczy na ekranie i pozwalający użytkownikowi na interakcję z nim, w ogóle nie określa miejsca do przechowywania . Większość frameworków MVC to frameworki z pełnym stosem, które wykraczają poza zwykłe MVC i pomagają w przechowywaniu danych, a ponieważ dane, które powinny być przechowywane, zwykle znajdują się w modelu, ramy te zapewniają wygodne sposoby przechowywania modelu dane w bazie danych, ale nie ma to nic wspólnego z MVC. W idealnym przypadku modele powinny być niezależne od trwałości, a przejście na inny typ pamięci nie powinno w ogóle wpływać na kod modelu. W pełni rozwinięte architektury mają warstwę trwałości do obsługi tego.
Waquo
źródło
4
Większość frameworków MVC w pewnym sensie miesza wszystkie elementy pamięci / bazy danych w modelu, aby ułatwić przechowywanie modeli (często przez rozszerzenie klas frameworków). To prawdopodobnie jest źródłem zamieszania. Technicznie, kod modelu, który piszesz, powinien być rzeczywistym modelem (warstwa domeny), podczas gdy kod dostarczany przez framework powinien zajmować się pamięcią masową (warstwa trwałości). Na przykład coś takiego jak User.find (...) (z użytkownikiem, który jest modelem) działa, ponieważ środowisko zaimplementowało wzorzec repozytorium jako część modelu.
Waquo,
3
View-Controller-Model-Storage to ogólna zasada (chociaż związek między M, V i C powinien być zwizualizowany jako trójkąt). Kiedy Twój framework miesza pamięć w swój „model”, działa to mniej więcej tak: View-Controller- (Model dziedziczy pamięć po frameworku).
Waquo,
2
View-Controller-Model-Storage jest raczej prymitywny, ponieważ nie powinien być płaski. Na przykład, gdy kontroler robi coś takiego jak User.find (...), aby uzyskać model, pyta bezpośrednio warstwę pamięci zamiast przejść przez warstwę domeny.
Waquo,
2
W architekturach z bardziej ostrożnym nakładaniem warstw byłoby to jak UserRepository.find (). Przez „model” miałem na myśli klasę „model” dostarczoną przez framework, z którego dziedziczysz. User-obiekt zwrócony przez User.find () jest model użytkownika w tym sensie, że ktoś wzorowany co użytkownik jest, w jaki sposób użytkownik zachowuje ...
Waquo
1
@flipdoubt logika biznesowa to dowolna logika, która powinna pozostać taka sama, jeśli przeportowałeś z mvc, aby powiedzieć aplikację uwp.
Andy,
23

Ty i duża część świata programowania wydaje się źle rozumieć, jakie są role części MVC. Krótko mówiąc, są to:

Model = logika domeny

Widok = logika wyjściowa

Kontroler = logika wejściowa

Oznacza to, że model odpowiada za całą logikę biznesową: wszystko, co jest związane z rysowaniem widżetów na ekranie, sterowaniem drukarką, wysyłaniem danych w formacie HTML, analizowaniem żądań HTTP itp. Itd., Nie należy do modelu.

Jednak wiele nowoczesnych tak zwanych frameworków „MVC” tak naprawdę wcale nie robi MVC lub źle opisuje swoje części. Dość często to, co nazywa się „modelem”, to warstwa trwałości modelu, podczas gdy logika biznesowa opiera się na czymś, co nazywają „kontrolerem”; rzeczywisty kontroler jest zwykle tylko centralnym punktem wejścia z tabelą routingu i odrobiną kodu w poszczególnych „kontrolerach”, aby wysłać otrzymane dane wejściowe do właściwych procesów biznesowych. To, co te ramy nazywają „widokiem”, to tak naprawdę wszystko: trochę logiki prezentacji (Widok), trochę obsługi danych wejściowych i sprawdzania poprawności (Kontroler) oraz trochę więcej logiki biznesowej (Model). Lwia część rzeczywistego widoku jest zwykle nazywana „szablonami”.

Możesz także przeczytać o architekturze wielopoziomowej; gdzie MVC jest rodzajem jednokierunkowym (przepływ to Kontroler -> Model -> Widok), wielopoziomowy jest rzeczą dwukierunkową (Prezentacja -> Logika -> Dane -> Logika -> Prezentacja) i całkiem sporo frameworki, które udają, że robią MVC, w rzeczywistości wykonują Trójwarstwowe, zmieniając etykiety Prezentacja do wyświetlenia, Logika do kontrolera i Dane do modelu.

tdammers
źródło
2
Wierzę, że źle przedstawicie Model („Model = logika domeny”), moim zdaniem jest to raczej naczynie dla populacji z danymi, które następnie są renderowane przy użyciu Widoku, w najczystszej postaci wzorca MVC. Oczywiście w bardzo prostych przypadkach użycia można to potraktować jako „logikę domeny”, ale gwarantuję, że większość istniejących systemów wyrósłaby tak szybko. Lepiej podzielić „logikę domeny” na osobną warstwę / klasę, np. Warstwę usługową.
A. Murray,
@ A.Murray: Oczywiście Model nie musi być jedną monolityczną kroplą kodu, a rozdzielenie go na trwałość, struktury danych i logikę domeny zwykle ma sens. Mimo to MVC grupuje te trzy problemy razem w Modelu. W każdym razie, gdy kontrolery i widoki zawierają logikę domeny, nie jest to już prawdziwy MVC.
tdammers
@tdammers, podoba mi się porządek twojej odpowiedzi i jej koncentracja na logice. Jakie są Twoim zdaniem problemy związane z aplikacją, takie jak trwałość i przetwarzanie transakcji? Wygląda na to, że MVC powinien być czteroliterowym akronimem, podobnie jak MVCS, gdzie S służy do obsługi.
flipdoubt
15

Aby naprawdę wyodrębnić logikę biznesową i oddzielić ją od infrastruktury warstwy prezentacji, powinna być hermetyzowana przez usługi aplikacji. Architektura MVC jest sposobem na wdrożenie warstwy prezentacji i powinna pozostać w tym zakresie, delegując całą logikę biznesową na te usługi aplikacji. Pomyśl o modelach widoków jako o przejściówkach między widokiem a danymi, które muszą być wyświetlane i / lub czytane. Kontroler pośredniczy w interakcji między modelami widoków, widokami i usługami aplikacji obsługującymi logikę biznesową.

Usługi aplikacji implementują biznesowe przypadki użycia i są oddzielone od warstwy prezentacji, niezależnie od tego, czy jest to MVC, czy coś innego. Z kolei usługi aplikacji mogą obsługiwać skrypty transakcyjne lub projekty oparte na domenie .

W przypadku przechowywania usługa aplikacji może odwoływać się do repozytorium lub dowolnej abstrakcji mechanizmu trwałości. Różne implementacje mogą być wspierane poprzez abstrakcyjny dostęp do danych do interfejsu. Zazwyczaj te abstrakcje są nieszczelne i są tylko częściowo przenośne w różnych implementacjach i często jest to daremna próba uzyskania pełnej przenośności.

AKTUALIZACJA

Moja sugestia oparta jest na architekturze heksagonalnej . W architekturze heksagonalnej model domeny (logika biznesowa) stanowi rdzeń. Ten rdzeń jest zamknięty w usługach aplikacyjnych, które działają jak fasada . Usługi aplikacji to proste klasy, które mają metody odpowiadające przypadkom użycia w Twojej domenie. Aby uzyskać dogłębną dyskusję na temat usług aplikacji, zobacz Usługi w projektowaniu opartym na domenie . Przykładowy kod zawiera PurchaseOrderServiceusługę aplikacji dla domeny zakupów. (Należy pamiętać, że usługa aplikacji nie oznacza użycia projektowania opartego na domenie).

W architekturze heksagonalnej warstwa prezentacji MVC jest adapterem między modelem domeny (logiką biznesową) a GUI. Model domeny nie zna warstwy prezentacji, ale warstwa prezentacji zna model domeny.

To rozwiązanie ma z pewnością części ruchome niż rozwiązanie, które umieszcza logikę biznesową w kontrolerze, dlatego należy rozważyć wady i zalety. Sugeruję, że powodem tego jest to, że wolę oddzielić logikę biznesową od warstwy prezentacji w celu zwalczania złożoności. Staje się to coraz ważniejsze wraz z rozwojem aplikacji.

eulerfx
źródło
Wygląda na to, że opisujesz drania MVC i MVVM, który ma zarówno kontrolery, jak i modele wyświetlania. Myślę też, że architektura, którą opisujesz, może być nieco trudna dla potrzeb OP.
Waquo
szczerze mówiąc, bardziej podoba mi się odpowiedź Waquo. Głównie dlatego, że nie mam pojęcia, co masz na myśli przez „usługi aplikacji”. Czy możesz wyjaśnić ten termin? Mój GoogleFU nie działa tutaj, jak się wydaje.
Steffen Winkler,
1
@Waquo Zgadzam się, że proponowana architektura może być przesada, jednak należy to wziąć pod uwagę. Nie wspomniałem o MVVM, który jest po prostu innym sposobem na implementację warstwy prezentacji. Usługi aplikacji obowiązują niezależnie od tego, czy korzystasz z MVC czy MVVM i nic, co zasugerowałem, nie wskazuje na żadną ich kombinację.
eulerfx
1

Zależy od tego, co rozumiesz przez logikę biznesową. Każda „logika”, która nadaje znaczenie treści modelu, powinna znajdować się w modelu. W połączonym pytaniu najwyżej głosowana odpowiedź wydaje się definiować „logikę biznesową” jako cokolwiek związanego z danymi; ma to sens z punktu widzenia tego, że dane firmy to jej sprawa!

Kiedyś widziałem przykład twórcy Railsów (tak myślę), który robił dokładnie o tym - nie wprowadzając do modelu „logiki biznesowej”. Jego przykładem była klasa kontrolera oraz metoda rejestracji aplikacji i logowania - dostarczone hasło w postaci zwykłego tekstu zostało zaszyfrowane przed włożeniem lub zapytaniem o model (bazę danych).

Nie mogę wymyślić lepszego przykładu czegoś, co nie jest logiką kontrolera i które należy bezpośrednio do modelu.

Model może być interfejsem do niezliczonych magazynów danych, łagodząc obawy związane z przenośnością. To tutaj można znaleźć zamieszanie w związku z tym, czy nie, interfejs modelu jest w rzeczywistości „kontrolerem”.

Ogólnie rzecz biorąc, kontroler łączy model i widok (które są mięsem i ziemniakami aplikacji). W rozwoju Cocoa może być uproszczone do tego stopnia, że ​​kontroler jest obsługiwany przez GUI XCode (obiekty kontrolera i powiązania).

Sekcja „Wzory projektowe” GoF na MVC, luźno cytowana:

Triada klas MVC służy do budowania interfejsów użytkownika w Smalltalk-80. Model jest obiektem aplikacji, widok jest prezentacją na ekranie, a kontroler określa sposób, w jaki interfejs użytkownika reaguje na dane wprowadzone przez użytkownika. MVC oddziela widoki i modele, ustanawiając między nimi protokół subskrypcji / powiadamiania. Poniższy schemat przedstawia model i trzy widoki. Dla uproszczenia pominęliśmy sterowniki.

W MVC chodzi o interfejsy użytkownika. Nacisk kładziony jest na model i widok - definiowanie i wyświetlanie danych. Zwróć uwagę na „protokół subskrybowania / powiadamiania” - tutaj przychodzi twój kontroler. Możesz zbudować wszystkie potrzebne widoki; tak długo, jak będą przestrzegać protokołu, nigdy nie będziesz musiał dotykać modelu ani kontrolera.

Jeśli chodzi konkretnie o tworzenie stron internetowych, wiele popularnych frameworków internetowych IMHO szybko i luźno posługuje się terminem MVC i jego definicjami komponentów.

Książę
źródło
Jestem programistą C # / Java (tylko kilka projektów). Wygląda na to, że źle zrozumiałem, co robi model. Umieszczenie „logiki biznesowej” w kontrolerze naprawdę było tylko następstwem (mój ciąg myśli poszedł „dobrze”, mam model danych (czytaj: połączenie / przechowywanie bazy danych), więc moja logika biznesowa musi dostać się do kontrolera, ponieważ Muszę go zastosować przed zapisaniem danych w bazie danych. ”Wystarczy przenieść wszystko o jeden poziom niżej od kontrolera. Właściwie to rozwiązuje problem, który aktualnie miałem (obsługa MySQL i MSSQL w jednym programie)
Steffen Winkler,
0

Dlaczego nie wprowadzisz warstwy usług?

Wtedy twój kontroler będzie szczupły i bardziej czytelny, wtedy wszystkie funkcje kontrolera będą czystymi działaniami.

Możesz rozłożyć logikę biznesową tyle, ile potrzebujesz w warstwie usługi. Ponowne użycie kodu jest lepsze i nie ma wpływu na modele i repozytoria.

Indygowiec
źródło