Czy logika biznesowa może nie wkradać się do widoku?


31

Przez ostatnie 3 lata opracowywałem kilka projektów aplikacji internetowych, zarówno osobistych, jak i zawodowych, i wydaje mi się, że nie mogę zrozumieć, czy możliwe jest, że przynajmniej część logiki biznesowej nie znajdzie się w warstwie widoku aplikacji.

W większości przypadków wystąpią problemy, takie jak: „Jeśli użytkownik wybrał opcję x, to aplikacja musi umożliwić mu podanie informacji dla y, jeśli nie, to on / ona powinien podać informacje z”. Lub wykonaj pewne operacje AJAX, które powinny zastosować pewne zmiany w modelu, ale NIE zatwierdzaj ich, dopóki użytkownik wyraźnie tego nie zażąda. To jedne z najprostszych problemów, jakie napotkałem i nie mogę zrozumieć, jak można uniknąć złożonej logiki w widoku.

Większość książek, które przeczytałem o MVC, zwykle przedstawia kilka bardzo trywialnych przykładów, takich jak operacje CRUD, które tylko aktualizują dane na serwerze i wyświetlają je, ale CRUD nie występuje w większości bogatych aplikacji.

Czy jest możliwe uzyskanie widoku bez logiki biznesowej?


2
Spójrz na pochodne MVC MVP i MVVM (patrz en.wikipedia.org/wiki/Model_View_Presenter i en.wikipedia.org/wiki/Model_View_ViewModel ), mogą być tym, czego szukasz.
Doc Brown

powiązane (prawdopodobnie duplikat): Oddzielenie klas od interfejsu użytkownika
gnat

2
Widok jest zewnętrzną, widoczną manifestacją twoich danych i logiki. Widok NIE może przedstawiać logiki biznesowej. A może mówisz, że widok nie powinien zawierać żadnego kodu? Z pewnością możesz tworzyć widoki tylko w języku HTML.
BobDalgleish

Możesz zajrzeć do animacji szablonu ; Chociaż prawdopodobnie nie wyeliminuje to całej logiki z warstwy widoku , wygląda na to, że powinno to prowadzić do nieco lepszego oddzielenia rzeczy.
Paul

Wydaje mi się, że lepszym pytaniem jest to, czy lepiej wyświetlić dane, aby skazić model, czy też lepiej, aby widok zawierał logikę widoku związaną z logiką biznesową? To jest bardziej realistyczny scenariusz. Twoje pytanie zasadniczo opowiada się za zanieczyszczeniem modelu w celu poparcia poglądów, ponieważ byłby to jedyny sposób na osiągnięcie tego, o co pytasz.
Dunk

Odpowiedzi:


22

Czy jest możliwe uzyskanie widoku bez logiki biznesowej?

Odpowiedź na to zwodniczo trudne pytanie. (Prowokujące pytanie!)

Teoretycznie tak, w zależności od tego, co definiujemy jako logikę biznesową. W praktyce ścisłe oddzielenie staje się znacznie trudniejsze, a może nawet niepożądane.

Oddzielenie problemów to świetny sposób na zastanowienie się nad budowaniem oprogramowania: dostarcza pomysłów na temat tego, gdzie umieścić kod, a także daje opiekunom dobry pomysł na to, gdzie szukać kodu. Będę argumentować, że w zasadzie ludzie nie mogą zbudować działającego oprogramowania bez oddzielenia problemów. Potrzebujemy tego.

Ale, podobnie jak w przypadku wszystkich rzeczy, występują kompromisy. Najlepsza lokalizacja koncepcyjna może nie być najlepszą lokalizacją z innych powodów. Być może na twoim serwerze internetowym jest zbyt dużo obciążenia, więc dodajesz na swoich stronach trochę javascript, aby wychwycić łatwe błędy wejściowe, zanim trafią na twój serwer; teraz masz w swoim odczuciu logikę biznesową.

Sam widok sam w sobie nie ma wartości bez logiki biznesowej. Aby być skutecznym w użyciu i wyświetlaniu, w sposób dorozumiany lub jawny, widok będzie miał wiedzę na temat zachodzących procesów biznesowych. Możemy ograniczyć tę wiedzę i wyodrębnić jej fragmenty, ale względy praktyczne często zmuszają nas do „zerwania” rozdziału obaw.


2
The best conceptual location may not be the best location for other reasons: Brawo !!
Magno C

8

Zazwyczaj robię to: jeśli użytkownik wybrał opcję x, widok wywołuje

controller->OptionXChanged()

Następnie kontroler włącza y w widoku:

view->SetEnableInfoY(True) // suppose False=SetDisable

Widok powiadamia kontrolera o tym, co się dzieje, nie podejmując żadnych decyzji.


+1. Trywialne problemy OP byłyby zwykle rozwiązywane w ten sposób w nietrywialnej aplikacji
dev_feed

Umieszczenie tej logiki w kontrolerze ma dwa problemy: 1) komplikuje testowanie jednostkowe i nie można obsługiwać wielu widoków tych samych danych.
kevin cline

4

Pytam, czy przykłady, które opisujesz, są naprawdę logiką biznesową. Opisane przykłady to operacje, które można wykonać w systemie. To, w jaki sposób zdecydowałeś się przedstawić użytkownikowi opcje, które może sprawiać wrażenie logiki biznesowej w widoku.

Z punktu widokowego „Widok” dostarcza tylko system InfoY lub InfoZ do systemu. Tylko dlatego, że twoja implementacja interfejsu użytkownika wykonuje kilka dynamicznych aktualizacji w oparciu o wybór operatora (tj. Włączenie InfoY lub InfoZ), nie czyni logiki biznesowej funkcjonalności. To naprawdę widok logiki implementacji. Równie dobrze mogłeś po prostu dać operatorowi wybór na wejście do InfoY lub InfoZ bez całej aktywacji. Czy w tym kontekście nadal uważałbyś to za logikę biznesową? Jeśli nie, to samo dotyczy dynamicznego włączania / wyłączania pól informacyjnych.

To samo dotyczy przykładu zatwierdzenia. Są to 2 oddzielne operacje, których działanie wymaga system. Twój widok musi być w stanie zainicjować odpowiednie działania, aby wykonać pożądaną funkcjonalność. Czy umiejętność korzystania z systemu oznacza przeciek logiki biznesowej? Widzę, jak ktoś mógłby powiedzieć „tak”, ale jeśli wierzysz w ten sposób, rzeczywistość jest taka, że ​​nie ma czegoś takiego jak oddzielenie logiki biznesowej od czegokolwiek. Musisz wiedzieć, z czym robi / pracuje system, aby osiągnąć coś sensownego. W przeciwnym razie utworzenie pojedynczego ogólnego widoku i kontrolera działającego z każdą możliwą aplikacją MVC byłoby bardzo proste. Które wiemy, że jest niemożliwe.

Podsumowując, myślę, że twoja definicja logiki biznesowej nie jest taka sama jak innych definicji.


1

Pracuję w ten sposób (Struts2 + Hibernacja):

My Struts Actions odpowiada tylko za wyświetlanie informacji w przeglądarce internetowej. Nie myśląc.

Użytkownik -> Akcja -> Usługa -> Repozytorium -> Dostęp do danych

Lub:

Chcę zobaczyć -> Jak zobaczyć -> Co robić -> Jak zdobyć -> Gdzie zdobyć

Tak więc w pierwszej warstwie (widok) mam coś takiego:

public String execute ()   {
    try {
        CourseService cs = new CourseService();
        Course course = cs.getCourse(idCourse);
    } catch (NotFoundException e) {
        setMessageText("Course not found.");
    } catch (Exception e) {

    }
    return "ok";
}

Jak widzisz, mój „pogląd” nie myśli. To prosi o usługę (do zarządzania kursami) konkretnego kursu. Ta usługa może zrobić wiele innych rzeczy, takich jak raporty, usługi i tak dalej. Wynikiem jest zawsze lista lub określony obiekt (jak w przykładzie). Usługi są prawdziwą maszyną, stosują reguły i mają dostęp do repozytorium (w celu zarządzania danymi).

Tak więc, jeśli umieszczę moje Usługi, Repozytoria i DAOS w różnych bibliotekach, będę mógł ich używać nawet w programie tekstowym lub systemie stacjonarnym opartym na Windowsie, który niczego nie zmieni.

Serwis wie, co robić, ale nie wie, jak to pokazać. Widok wie, jak pokazać, ale nie wie, co robić. To samo z usługą / repozytorium: usługa wysyła i żąda danych, ale nie wie, gdzie są dane i jak je zabrać. Repozytorium „uzupełnia” nieprzetworzone dane do obiektów biznesowych, aby usługa mogła z nimi pracować.

Ale repozytorium nic nie wie o bazie danych. Rodzaj bazy danych (MySQL, PostgreSQL, ...) dotyczy DAO.

Możesz zmienić DAO, jeśli chcesz zmienić bazę danych i nie może ona wpływać na górne warstwy. Możesz zmienić repozytorium, jeśli chcesz zaktualizować zarządzanie danymi, ale nie może to wpłynąć na DAO i wyższe warstwy. Możesz zmienić Usługi, jeśli chcesz zmienić logikę, ale nie może to zepsuć się warstwami powyżej lub poniżej.

I możesz zmienić wszystko w widoku, nawet technologię (sieć, pulpit, tekst), ale nie może to sugerować niczego poniżej.

Logiką biznesową jest usługa. Ale jak z tym współdziałać, to przeglądać. Jaki przycisk pokazać teraz? Czy użytkownik może zobaczyć ten link? Myślisz, że twój system jest programem konsolowym: musisz zaprzeczyć, jeśli zły użytkownik wybierze #> myprogram -CourseService -option=getCourse -idCourse=234lub zatrzymać go, aby naciskał klawisze, aby napisać to polecenie?

Mówiąc w systemach internetowych (Struts + JavaEE) mam osobny pakiet kontrolera GUI. W widoku Działanie daję zalogowanemu użytkownikowi, a klasa daje mi przyciski (lub dowolny element interfejsu, który chcę).

                <div id="userDetailSubBox">
                    <c:forEach var="actionButton" items="${actionButtons}" varStatus="id">
                        ${actionButton.buttonCode}
                    </c:forEach>
                </div>

I

private List<ActionButton> actionButtons;

Pamiętaj, aby trzymać to z daleka od usług. To jest WIDOK. Trzymaj go w Akcjach Struts. Wszelkie interakcje interfejsu muszą być całkowicie oddzielone od prawdziwego kodu biznesowego, więc jeśli przeniesiesz swój system, łatwo będzie wyciąć to, czego już nie potrzebujesz.


1

W większości przypadków wystąpią problemy, takie jak: „Jeśli użytkownik wybrał opcję x, to aplikacja musi umożliwić mu podanie informacji dla y, jeśli nie, to on / ona powinien podać informacje z”

To jest logika modelu, a nie widok. Może to być „model widoku” stworzony specjalnie w celu obsługi interfejsu użytkownika, ale nadal jest to logika modelu. Sekwencja kontrolna to:

  • Kontroler dołącza moduł obsługi do wyświetlania zdarzeń
  • Zobacz dołącza moduł obsługi zdarzeń modelowych
  • Użytkownik wybiera opcję X.
  • Widok wywołuje zdarzenie „Wybrano opcję X”
  • Kontroler odbiera zdarzenie i wywołuje model.selectOptionX ()
  • Model wywołuje zdarzenie „Stan modelu zmieniony”
  • Widok odbiera zdarzenie zmiany modelu i aktualizuje widok, aby dopasować go do nowego stanu: inputY.enable(model.yAllowed()); inputZ.enable(model.zAllowed());

UI View Controller Model |.checkbox X checked.> | | | | | .. X selected ...>| | | | |-----> set X ------->| | | | | | |< .............state changed ............| | | | | | |-------------- Get state --------------->| | | | | | |<----------- new state ------------------| | <-- UI updates ------| To klasyczny wzór MVC. Możliwe jest całkowite przetestowanie logiki modelu oddzielnie od interfejsu użytkownika. Kontroler i widok są bardzo cienkie i łatwe do przetestowania.

=== W odpowiedzi na Dunk ===

Model w deseń UI MVC jest (zazwyczaj) nie model obiektu biznesowego. To tylko model stanu interfejsu użytkownika. W aplikacji komputerowej może zawierać odniesienia do wielu modeli biznesowych. W aplikacji Web 2.0 jest to klasa JavaScript, która przechowuje stan interfejsu użytkownika i komunikuje się z serwerem za pomocą AJAX. Bardzo ważna jest możliwość ręcznego testowania jednostkowego modelu stanu interfejsu użytkownika, ponieważ tam właśnie znajduje się większość błędów interfejsu użytkownika. Widok i kontroler powinny być bardzo cienkimi złączami.


1
Myślę, że wszystko sprowadza się do tego, co według ciebie jest definicją MVC. Ta wersja zdecydowanie spełnia bardzo, bardzo ścisłą interpretację MVC. Problem polega na tym, że ta ścisła interpretacja rzadko zapewnia użyteczny lub możliwy do utrzymania system w prawdziwym życiu. Powodem jest to, że prawie za każdym razem, gdy wymyślisz nowy element / sposób interfejsu użytkownika, musisz zmienić model. Model jest wówczas zaśmiecony niepotrzebnymi właściwościami istotnymi tylko dla interfejsu użytkownika. Nie mają one nic wspólnego z aplikacją, którą próbujesz zbudować, ale tylko z tym, jak chcesz prezentować dane operatorowi. ZŁY!
Dunk

kevin, proszę wstaw swoje odpowiedzi tutaj w polu komentarzy, więc łatwo nam odpowiedzieć. Zgadzam się z Tobą. Nie można zachować informacji o interfejsie (UI) bez jakiejkolwiek struktury, ale nomenklatura „MODEL” może być myląca. Wolę zarządzać elementami interfejsu użytkownika w innym wymiennym pakiecie, aby łatwo robić to, o czym mówi @Dunk. Zobacz moją odpowiedź.
Magno C

@MagnoC: Zredagowałem jego odpowiedź w odpowiedzi na Dunka, ponieważ myślałem, że dodany tekst poprawił odpowiedź. O to właśnie chodzi w tej witrynie: pytania i odpowiedzi. Model jest dość ogólnym terminem, a we wzorze MVC oznacza „model stanu interfejsu użytkownika”.
kevin cline

0

Logika biznesowa jest bardziej podobna If X then return InfoType.Y, wówczas interfejs użytkownika wyświetla pola na podstawie wyników zwróconych przez domenę.

// Controller method pseudocode
option changed routine

    get selected option

    get required info type from domain routine based on selected option

    display fields based on required info type

Jeśli interfejs użytkownika wymaga logiki biznesowej, deleguj wybór do domeny. Interfejs użytkownika będzie po prostu działał na podstawie decyzji.


0

Jeśli użytkownik wybrał opcję x, aplikacja musi umożliwić mu podanie informacji dla y, jeśli nie, to on / ona powinien podać informacje z ".

Istnieją dane wejściowe, które mają warunkowo oparte wymagane wartości. W większości środowisk GUI istnieje wiele możliwości wyboru sposobu obsługi danych wejściowych, zwłaszcza taktowania. Wybrana opcja (w tym przypadku x) musi zostać przetworzona, więc wyślij ją do kontrolera. Wyślij go, gdy użytkownicy opuszczą pole wprowadzania. Poczekaj, aż klikną inny obiekt lub klikną przycisk Zapisz. Nie ma znaczenia dla logiki biznesowej. Tak czy inaczej, kontroler podejmie decyzję i musi powiedzieć widokowi „y jest wymagane”.

Sposób, w jaki widok interpretuje lub implementuje, nie ma tak naprawdę znaczenia z logiki biznesowej. Wpisz wymagane pole. Zrób wyskakujące okienko lub zestrzel armatę i powiedz użytkownikowi, aby wszedł lub po prostu bądź uparty i nie pozwól biednemu użytkownikowi nic zrobić, dopóki się nie zorientuje.

I pomyśl tylko, że wszystko to mogło się zdarzyć, ponieważ kontroler próbował zapisać i nie wprowadził wartości dla wymaganego pola w bazie danych i reagował wyłącznie na błąd bazy danych. To nie ma znaczenia, jeśli chodzi o widok.

Coś w rodzaju wymaganej lub ograniczonej wartości wejściowej może być obsługiwane w wielu miejscach. Jeśli rozwiążesz to tylko w widoku, wielu programistów uzna to za problem, gdy może istnieć wiele interfejsów użytkownika. Dlatego logikę biznesową można tworzyć i testować bez większego interfejsu użytkownika, a nawet bazy danych. Nie musisz nawet mieć strony internetowej.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.