MVC: Gdzie umieścić logikę biznesową? [Zamknięte]

81

Przede wszystkim widziałem wiele pytań na ten temat, ale niewystarczające uzasadnienie. Jeśli moje pytanie nie jest wystarczająco dobre i powinno zostać usunięte, zrozumiem.

Przyjrzałem się na przykład temu i ponad 45 głosowanej odpowiedzi mówi, że radzi on umieścić logikę biznesową w modelu, co brzmi całkiem logicznie.

Jednak mój pierwszy duży projekt zrobiłem z całym moim BL w pełni w kontrolerach, ponieważ nie kwestionowałem tych rzeczy i patrzyłem, jak to się robi w tym, AccountControllerktóry jest automatycznie dodawany, jeśli wybierzesz MVC z uwierzytelnianiem formularza. Wszystkie metody wyglądają na całkiem wypchane BL. A może jest to najmniejsza ilość kodu, jaką udało mi się dodać i coś przeoczam?

Ktoś na youtube zapytał mnie, czy ma rację, umieszczając całą logikę w swoich modelach i na początku nie! Wtedy zacząłem myśleć, że może miał rację !?

Więc w końcu gdzie umieścić swoją logikę biznesową? Jeśli jest w klasach modeli, to ile kodu należy uznać za zdrową ilość w metodzie, która jest w kontrolerze? Jedna linia do wywołania co najwyżej jakiejś metody z modelu w kontrolerze, a potem powrót do widoku?

Andrius Naruševičius
źródło
1
Logika biznesowa idzie do kontrolerów. Logika modelu jest umieszczana w modelu. Logika modelu to rzeczy, które dotyczą konkretnego modelu / tylko. Settery / getters / properties / adders / remover, etc.
zmiażdżyć
1
@crush: Nie zgadzam się. Jak czytałem - „Obiekt modelu przechowuje dane aplikacji i„ logikę biznesową ”.
Oraz
@BobbyDigital - czy możesz podać link do źródła? :)
Andrius Naruševičius
Jasne, jest to wyjaśnienie prawidłowego użycia MVC w przewodniku The Big Nerd Ranch, ale niestety będziesz musiał kupić książkę, aby to potwierdzić.
ChiefTwoPencils
Powiem jednak, po prostu próbując to potwierdzić w książce C #, w asp.net logika biznesowa przechodzi w środkowej warstwie, gdzie górna warstwa byłaby interfejsem użytkownika, środkowa byłaby kontrolerem, a dolna byłaby db. Ale nie mówią konkretnie / otwarcie o MVC. To pochodzi z C # dla programistów :)
ChiefTwoPencils

Odpowiedzi:

54

Wolę umieścić logikę domeny w modelu z kilku powodów.

  1. Model nie powinien zawierać kodu interfejsu użytkownika, a zatem powinien być łatwiejszy do przetestowania. Zawsze, gdy jest to możliwe, wolę mieć w pełni działający model (co oznacza pełne pokrycie testami) przed napisaniem kodu interfejsu użytkownika. Kontroler może ufać, że model działa właściwie i po prostu radzi sobie z problemami związanymi z interfejsem użytkownika.

  2. Jeśli umieścisz logikę domeny w kontrolerze, udostępnianie jej między różnymi aplikacjami lub nawet między różnymi kontrolerami nie będzie tak łatwe.

Ferruccio
źródło
2
Tak, bardzo mi się podobało, #2ponieważ sam ciężko mi było dzielić się między kontrolerami (musiałem używać takich metod jak statyczne)!
Andrius Naruševičius
Tak @ AndriusNaruševičius, nie rób tego. Powinieneś spróbować wstrzyknąć swoje zależności do kontrolerów i nie polegać na innych kontrolerach.
Mark Walsh,
Zauważ, że myślę, że ta odpowiedź mówi o „modelach domeny” (część M klasycznego wzoru MVC), co jest czymś, co nie ma związku z „modelem” ASP.Net MVC (częścią wzorca MVVM).
Alexei Levenkov
1
Więc ... gdzie umieszczasz logikę, która opiera się na wielu modelach?
Kolob Canyon
1
@Ferrucio To złe rozwiązanie. Skończysz w „piekle zależności”, w którym tworzysz obiekty, których tworzenie zależy od innych obiektów. To złe rozwiązanie, ponieważ niepotrzebne / nieużywane dane są przekazywane bez powodu. Chcesz, aby funkcje pobierały tylko to, czego potrzebują do wykonania zadania - w przeciwnym razie kod bardzo szybko stanie się niejasny. Lepszym rozwiązaniem jest tworzenie klas logiki biznesowej, których konstruowanie zajmuje absolutne minimum (lub jeszcze lepiej, użycie iniekcji zależności do konstruowania). W ten sposób nigdy nie będziesz musiał pobierać kilku niepowiązanych ze sobą obiektów w celu wykonania logiki biznesowej.
Kolob Canyon
43

Lubię utrzymywać moje modele w czystości, tj. Tylko z właściwościami i bez logiki biznesowej. Zawsze uważam, że dobrze jest wstrzyknąć zależności do kontrolera, a te zależności zawierają logikę, którą wykonuję na moich modelach. Lubię trzymać się zasady pojedynczej odpowiedzialności tam, gdzie to możliwe, i uważam, że modele z mnóstwem metod bardzo szybko się rozrastają. W obu przypadkach są plusy i minusy, wstrzyknięcie wielu zależności wiąże się z narzutem, ale pozwala na testowanie w izolacji i sprawia, że ​​zajęcia są proste, a skończy się to na szczuplejszych kontrolerów. Pomimo mojej logiki, która tak naprawdę nie istnieje w moim modelu jako członkowie klasy, nadal jest to logika biznesowa. Zwykle nie mam zdefiniowanej logiki biznesowej w kontrolerze, ponieważ kpiny, takie jak Httpcontext, są trochę koszmarem i niepotrzebne.

Mark Walsh
źródło
5
+1 zgadzam się całkowicie. Myślałam, że tylko ja lubię ograniczać obowiązki modelek do minimum!
Lee
1
Jasne, on jest istotą mojego kontrolera logowania gist.github.com/markwalsh-liverpool/8fb361a9df0dcf034caf
Mark Walsh
1
Więc jeśli nie umieścisz logiki w swoich modelach lub kontrolerach - gdzie to umieścisz?
niico
1
W jaki sposób przekazujesz argumenty do konstruktora kontrolera? Czy inicjalizacja kontrolera nie jest zwykle wykonywana za kulisami?
Jeff,
1
Używam zastrzyku zależności.
Mark Walsh,
23

Plik Biznesowych logika należy do domeny problemu i wszystko, co należy do dziedziny problemu przechodzi do modelu w MVC.

Plik Kontroler powinien być odpowiedzialny za przekazywanie danych z modelu do widoku iz widoku Powrót do modelu. Kontroler jest więc pomostem między tym, z czym użytkownik wchodzi w interakcje, a sposobem modelowania i zapisywania stanu problemu przez program. Hydraulika , że tak powiem.

Kluczem jest tutaj rozróżnienie między logiką biznesową a logiką hydrauliczną. Moim zdaniem to, co robi automatycznie generowany kontroler konta, to głównie hydraulika, a nie logika biznesowa. Należy pamiętać, że logika hydrauliczna niekoniecznie jest w ogóle krótka, więc nie trzeba narzucać sztucznych ograniczeń (np. „X liczba wywołań maksymalnie w kontrolerze”).

Theodoros Chatzigiannakis
źródło
Zgadzam się z tym wszystkim. Jednak myślę, że wiele nieporozumień wynika z tego, jak ustrukturyzować klasy w modelu, szczególnie w przypadku EF. IE: czy używasz klas częściowych i budujesz logikę w różnych plikach C #? jeden plik dla EF i jeden plik dla logiki?
S1r-Lanzelot
13

Mój zespół po przeniesieniu się do MVC z formularzy internetowych (asp.net) przeprowadził wiele badań i opracował następującą strukturę. Według mnie nie chodzi o to, jak duża czy mała jest aplikacja. Chodzi o to, aby kod był czysty i przejrzysty.

DALProject

AccountsDAL.cs --- > Calls SP or any ORM if ur using any

BLLProject

AccountsBLL.cs ---> Calls DAL

WebProject

Model
    AccountsModel --- > Contains properties And call BLL
Controllers
    IndexController ---> Calls Models and returns View
Views
    Index

Kontrolerzy powinni odpowiadać za przekazywanie danych między modelem a widokiem. Poza tym nie powinno być żadnego zbędnego kodu. Na przykład, jeśli rejestrujesz, należy to zrobić na poziomie modelu, a nie na kontrolerze.

Muneeb Zulfiqar
źródło
13

Wydaje się, że istnieje pewne zamieszanie wokół tego tematu. W większości wydaje się, że ludzie mylą wzorzec MVC z architekturą N-warstwową jako sytuację „albo / albo”. W rzeczywistości te dwa podejścia mogą być używane razem, ale jedno nie jest zależne od drugiego i żadne nie jest wymagane.

Architektura N-warstwowa polega na rozdzielaniu aplikacji na wiele warstw. Prostym przykładem jest podzielenie aplikacji na warstwę prezentacji, warstwę logiki biznesowej i warstwę dostępu do danych.

MVC to wzorzec projektowy dotyczący warstwy prezentacyjnej aplikacji. Całkowicie możliwe jest zaprojektowanie aplikacji zgodnie z podejściem MVC bez oddzielania logiki biznesowej i logiki dostępu do danych od warstwy prezentacji, a tym samym uzyskanie projektu jednopoziomowego.

W rezultacie, jeśli postępujesz zgodnie z podejściem MVC bez oddzielania aplikacji na warstwy, uzyskujesz modele, widoki i kontrolery, które mają bity reguł biznesowych i logiki dostępu do danych zmieszane z resztą logiki.

Z definicji w architekturze N-warstwowej warstwa prezentacji powinna być w stanie komunikować się tylko z warstwą logiki biznesowej, więc powinna utrzymywać, że dowolny z komponentów MVC może komunikować się tylko z warstwą logiki biznesowej.

Jeśli budujesz aplikację, która nie wymaga prezentacji, a więc nie jest warstwą prezentacji, nie powinieneś przejmować się wzorcem MVC. Jednak bardzo dobrze możesz nadal podzielić aplikację na wiele warstw, a tym samym podążać za projektem N-warstwowym, nawet jeśli nie jest to wymagana warstwa prezentacji.

treefiddy
źródło
8

Ogólnie rzecz biorąc, logika biznesowa nie powinna znajdować się w żadnym z odtwarzaczy MVC; powinien być używany tylko przez akcje kontrolera.

Jak wiele osób wspomniało, najlepiej jest utworzyć bibliotekę do obsługi logiki biznesowej jako zestaw niezależnych od klienta komponentów wielokrotnego użytku.

Robiąc to w ten sposób, znacznie zwiększamy możliwość ponownego użycia, kompatybilność, skalowalność i testowalność z naszym oprogramowaniem. Zmniejszamy również naszą zależność od niektórych funkcji frameworka, co ułatwia migrację do nowszych / innych technologii.

Abstrahowanie naszej logiki biznesowej w samodzielny zespół (lub zespoły) dobrze nam służyło przez lata. Nasza logika biznesowa może być następnie używana przez praktycznie każdą technologię .NET (ASP.NET MVC / API / Core, WPF, Win Forms, WCF, UWP, WF, Console itp.).

Ponadto lubimy, gdy nasza warstwa środkowa obsługuje reguły biznesowe i logikę walidacji, aby zmniejszyć nasze zależności od platformy .NET MVC Framework. Na przykład unikamy korzystania z pomocników walidacji .NET MVC i zamiast tego polegamy na własnych. To kolejny czynnik, który pozwala nam łatwo wykorzystać naszą logikę biznesową z dowolnej technologii .NET.

Logiczne zaprojektowanie naszej środkowej warstwy w ten sposób umożliwiło nam łatwe osiągnięcie takiej architektury fizycznej:

wprowadź opis obrazu tutaj

Został napisany za pomocą Peasy.NET i dobrze nam służył przez lata. Tak dobrze, że zdecydowaliśmy się to otworzyć.

Jeśli ktoś jest ciekawy, jak wygląda nasza środkowa kondygnacja, oto próbka od klienta warstwy biznesowej. Przedstawia również jego użycie przez wielu klientów .NET (ASP.NET MVC, Web Api i WPF).

Mam nadzieję, że to komuś pomoże!

ahanusa
źródło
Przeważnie nie ma potrzeby ponownego wykorzystywania logiki. Jeśli powiedzmy, że zdecyduję się użyć ASP.NET Core MVC dla interfejsu API sieci Web, nigdy nie będę chciał używać tej logiki biznesowej w WPF lub WinForms. Ponieważ klient i tak będzie się komunikował z serwerem. Umieszczanie logiki biznesowej, a zwłaszcza logiki dostępu do bazy danych po stronie klienta, jest po prostu złe.
Konrad
Powiedziałbym, że im więcej poziomów dodasz, zmniejsza to łatwość utrzymania i testowalność. W końcu testy integracyjne mają większe znaczenie.
Konrad,
8

Logika biznesowa nie powinna być umieszczana w widokach modeli ani kontrolerach. Powinna istnieć oddzielna warstwa logiki biznesowej ; jedynym celem tej warstwy jest obsługa logiki biznesowej. Jest to bardziej zgodne z SOLID .

Jeśli umieścisz logikę biznesową w MV lub C, otrzymasz kod, który jest trudny do przetestowania / ponownego wykorzystania.

A co z umieszczeniem logiki w modelach?

To jest złe rozwiązanie.

Skończy się w piekło zależności gdzie obiekty polegać na obiektach. wprowadź opis obrazu tutaj

Nawet jeśli masz martwą prostą funkcję, nadal będziesz musiał spełnić wszystkie zależności, aby ją wywołać.

Spowoduje również, że niepotrzebne i niewykorzystane dane będą przekazywane bez powodu.Może to również wpłynąć na wydajność w zależności od tego, jak bardzo się pogorszy.

Powinienem również wspomnieć, że testowanie jednostkowe staje się uciążliwe w a **, ponieważ musisz mockować wiele obiektów, aby przetestować prostą funkcję.

Obowiązujące zasady czystego kodu

  1. Klasy / funkcje przyjmują tylko to, czego potrzebują, aby wykonać zadanie.
  2. Funkcje powinny mieć maksymalnie 3 parametry, jeśli to możliwe
  3. Inteligentnie nazwij klasy / funkcje / zmienne (postępuj zgodnie ze standardami firmy Microsoft)
  4. Nie łącz logiki biznesowej z widokiem modelu lub kontrolerem

Kontrolery

W kontrolerze powinno być możliwe użycie iniekcji zależności w celu wstrzyknięcia warstwy logiki biznesowej . Upewnij się, że kontroler jest używany tylko do kierowania informacji do warstwy logiki biznesowej. Kontroler NIE powinien mieć bezpośrednio w sobie logiki biznesowej. Wszelkie walidacje muszą być obsługiwane przez IValidatablemodel. Każda logika biznesowa musi być skierowana do oddzielnej warstwy.

Kolob Canyon
źródło
Tutaj, gdzie pracuję, mamy warstwę biznesową i chciałem tylko, żebyśmy jej nie mieli. Warstwy biznesowe to czysty bałagan, logika powinna być wzorowa.
Mateus Felipe
@MateusFelipe Gdzie więc umieszczasz logikę, która wymaga wielu modeli (na przykład: płatności i produktu)? Czy tworzysz nowy model, który ma Paymenti Productjako zmienną instancji? Jak nazwiesz ten obiekt? Jeśli model nie jest używany w widoku, nie jest już modelem. Jest częścią osobnej warstwy. Idealnie byłoby, gdyby ta klasa, którą tworzysz, obejmowała tylko to, czego potrzebuje z płatności i produktu, aby wykonać swoją pracę. Jeśli potrzebuje tylko productNamei price, powinien przyjąć tylko te dwa parametry, a nie cały obiekt.
Kolob Canyon
4

Ogólna odpowiedź jest taka, że ​​logika biznesowa zwykle mieści się w dwóch kategoriach:

Logika biznesowa zorientowana obiektowo: jest modelowana jako obiekty (w modelu), zwykle wstrzykiwane jako repozytoria.

Proceduralna logika biznesowa: przechodzi do usługi z interfejsem, który można wstrzyknąć do kontrolera.

Logika kontrolera: Logika, która kontroluje, w jaki sposób polecenia są odbierane i przekazywane do modeli / usług, a następnie w jaki sposób te wyniki są przekazywane do widoku.

Kontrolery nie powinny mieć logiki biznesowej , jest to bardzo specyficzna część wzorca projektowego służąca do kontrolowania sposobu, w jaki interfejs użytkownika przekazuje dane wejściowe do modeli obsługujących logikę biznesową (lub usług, jeśli problemy mają charakter bardziej proceduralny).

WhiteleyJ
źródło
2

Lubię również utrzymywać moje modele w czystości (ref: @Mark Walsh). Problem braku możliwości ponownego użycia logiki osadzonej w kontrolerach można łatwo rozwiązać poprzez wstrzyknięcie zależności lub, jeśli uważasz, że byłoby tego za dużo, ujawnij logikę biznesową / domenową za pośrednictwem interfejsów i użyj wzorca fasady w kontrolerach. W ten sposób uzyskasz potrzebną funkcjonalność, ale zarówno kontrolery, jak i model będą ładne i czyste.

Bob H.
źródło
1

Wolałbym również, aby modele były czyste. Kontrolery MVC powinny być używane tylko do wykonywania połączeń i powinny być również utrzymywane w czystości. Tak więc w zależności od możliwości ponownego wykorzystania, wrażliwości i trafności logika biznesowa może zostać zapisana

1. Kontroler WebApi: Zaletą korzystania z kontrolera webapi jest to, że możesz później udostępnić je jako usługi innym urządzeniom, dzięki czemu kod będzie można ponownie wykorzystać.

2. BAL / Commonent: Istnieją pewne logiki, które mają określone zastosowanie i nie mogą być ujawniane jako API, które mogą być wypychane w tej klasie.

3. Repozytorium: Wszystkie zapytania dotyczące bazy danych są dodawane do repozytorium. Może istnieć repozytorium ogólne, które będzie implementowało wszystkie funkcje (operacje CRUD) lub określone repozytoria dla każdej tabeli. W zależności od operacji do wykonania.

Nikitesh
źródło
1

Jak napisał ahanusa, powinieneś umieścić swoją logikę biznesową w oddzielnej bibliotece DLL lub osobnym katalogu.
Często używam katalogu o nazwie Logika na tym samym poziomie modeli i kontrolerów, w którym umieszczam klasy obsługujące logikę biznesową.
W ten sposób wyczyściłem zarówno modele, jak i kontrolery.

Ryozzo
źródło
0

Wiem, że chodzi o MVC, ale myślę, że podany przeze mnie przykład (Web API) będzie przydatny.

Tworzę mój pierwszy internetowy interfejs API i ponownie używam logiki biznesowej z innych aplikacji. Mówiąc dokładniej, pochodzi z zewnętrznej biblioteki DLL, więc moje API służy tylko do „rozmowy” z rozwiązaniem SAP, odbierania żądań z PO i wysyłania odpowiedzi z powrotem.

Jak mogę umieścić moją logikę (już zaimplementowaną) w kontrolerze? Nie potrzebuję tego. Mój kontroler będzie tylko odbierał, sprawdzał żądania i tworzył odpowiedzi w celu odesłania danych.

Pracuję z klasami ViewModel i wszystko, co muszą mieć, to funkcja mapowania, tylko po to, aby odczytać informacje z TransferObjects (które pochodzą z zewnętrznej biblioteki DLL) i przetłumaczyć na ViewModel.

Nie czuję się komfortowo, gdy moja aplikacja (w tym przypadku Web API) trzyma logikę biznesową, myślę, że w ten sposób utracona zostanie możliwość ponownego użycia.

Traktuję swoją logikę biznesową jako zależność, którą wstrzykuję do kontrolera.

Dokonałem wielu refaktoryzacji w przeszłości, aby zapewnić rozwiązanie do testowania jednostkowego, musiałem stworzyć wiele interfejsów i zaimplementować pewne wzorce projektowe do starszych wersji, aby zapewnić to rozwiązanie.

Z mojego punktu widzenia warstwa biznesowa musi znajdować się poza aplikacją, najlepiej w innej bibliotece klas. Dzięki temu w Twojej aplikacji zostanie wdrożona prawdziwa koncepcja separacji.

Oczywiście, jeśli CORE (biznes) to Twoja aplikacja (API / WebSite) , reguły biznesowe zostaną zaimplementowane w Twoich klasach MVC. Ale w przyszłości, jeśli będziesz chciał stworzyć nową aplikację, a niektóre reguły biznesowe będą takie same, założę się, że będziesz miał wiele problemów z utrzymaniem tej samej logiki zaimplementowanej w obu aplikacjach.

Otta Augusto
źródło