Kann sich die Geschäftslogik nicht in die Ansicht einschleichen?

31

Ich habe in den letzten drei Jahren für mehrere Webanwendungsprojekte entwickelt, sowohl privat als auch beruflich, und ich kann anscheinend nicht herausfinden, ob es möglich ist, dass zumindest einige Geschäftslogiken nicht in der Ansichtsebene der Anwendung landen.

In den meisten Fällen treten Probleme wie "Wenn der Benutzer die Option x ausgewählt hat, muss die Anwendung ihm ermöglichen, Informationen für y einzugeben, wenn nicht, sollte er Informationen für z eingeben" auf. Oder führen Sie eine AJAX-Operation aus, bei der einige Änderungen am Modell vorgenommen, diese jedoch NICHT übernommen werden sollen, bis der Benutzer dies ausdrücklich angefordert hat. Dies sind einige der einfachsten Probleme, auf die ich gestoßen bin, und ich kann nicht herausfinden, wie es möglich ist, komplexe Logik in der Ansicht zu vermeiden.

Die meisten Bücher, die ich über MVC gelesen habe, enthalten in der Regel einige sehr triviale Beispiele, z. B. CRUD-Vorgänge, bei denen nur Daten auf dem Server aktualisiert und angezeigt werden. Bei den meisten umfangreichen Anwendungen ist CRUD jedoch nicht der Fall.

Ist es überhaupt möglich, eine Sicht ohne Geschäftslogik zu erreichen?

vdaras
quelle
2
Schauen Sie sich die MVC-Ableitungen MVP und MVVM an (siehe en.wikipedia.org/wiki/Model_View_Presenter und en.wikipedia.org/wiki/Model_View_ViewModel ), sie könnten das sein, wonach Sie suchen.
Doc Brown
Verwandte (möglicherweise ein Duplikat): Entkopplung von Klassen von der Benutzeroberfläche
gnat
2
Die Ansicht ist die äußere, sichtbare Manifestation Ihrer Daten und Ihrer Logik. Es ist nicht möglich, dass die Ansicht NICHT die Geschäftslogik darstellt. Oder sagen Sie, dass die Ansicht keinen Code enthalten sollte? Sie können natürlich nur HTML-Ansichten erstellen.
BobDalgleish
Sie könnten sich mit Vorlagenanimationen befassen . während dies wahrscheinlich nicht beseitigt alle Logik aus der Sicht Schicht , sieht es aus wie es zu etwas besseren Trennung der Dinge führen soll.
Paul
Ich denke, eine bessere Frage ist, ob es besser ist, wenn Ansichtsdaten das Modell verschmutzen, oder ob es besser ist, wenn die Ansicht Ansichtslogik enthält, die mit der Geschäftslogik zusammenhängt. Das ist das realere Szenario. Ihre Frage befürwortet im Wesentlichen die Verschmutzung des Modells, um Ansichten zu unterstützen, da dies der einzige Weg wäre, um das zu erreichen, was Sie sich wünschen.
Dunk

Antworten:

22

Ist es überhaupt möglich, eine Sicht ohne Geschäftslogik zu erreichen?

Ich finde diese Frage täuschend schwer zu beantworten. (Zum Nachdenken anregende Frage!)

Theoretisch ja, je nachdem, was wir als Geschäftslogik definieren. In der Praxis wird eine strikte Trennung viel schwieriger und möglicherweise sogar unerwünscht.

Die Trennung von Bedenken ist eine gute Möglichkeit, über das Erstellen von Software nachzudenken: Sie liefert Ihnen Ideen darüber, wo Code platziert werden soll, und sie gibt Betreuern eine gute Vorstellung davon, wo nach dem Code gesucht werden soll. Ich werde argumentieren, dass es für Menschen grundsätzlich unmöglich ist, funktionierende Software zu erstellen, ohne die Bedenken zu trennen. Wir brauchen das.

Aber wie bei allen Dingen gibt es Kompromisse. Der beste konzeptionelle Standort ist aus anderen Gründen möglicherweise nicht der beste Standort. Möglicherweise ist Ihr Webserver zu stark ausgelastet, sodass Sie Ihren Webseiten Javascript hinzufügen, um Eingabefehler zu erkennen, bevor sie auf Ihren Server gelangen. Jetzt haben Sie einige Geschäftslogik in Ihrer Ansicht.

Die Ansicht selbst hat ohne die Geschäftslogik keinen Wert. Damit die Ansicht implizit oder explizit effektiv verwendet und angezeigt werden kann, verfügt sie über Kenntnisse über die dahinter liegenden Geschäftsprozesse. Wir können diese Menge an Wissen begrenzen und Teile davon absperren, aber praktische Überlegungen zwingen uns oft, die Trennung von Bedenken zu „brechen“.

JvR
quelle
2
The best conceptual location may not be the best location for other reasons: Bravo !!
Magno C
8

Normalerweise mache ich das: Wenn der Benutzer die Option x ausgewählt hat, ruft die Ansicht auf

controller->OptionXChanged()

Dann aktivieren Sie den Controller in der Ansicht:

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

Die Ansicht benachrichtigt den Controller darüber, was passiert, ohne etwas zu entscheiden.

Fil
quelle
+1. Die trivialen Probleme von OP werden normalerweise in einer nicht-trivialen Anwendung wie
folgt behandelt
Das Einfügen dieser Logik in die Steuerung hat zwei Probleme: 1) Es erschwert das Testen von Einheiten, und es ist unmöglich, mehrere Ansichten derselben Daten zu unterstützen.
Kevin Cline
4

Ich frage mich, ob die von Ihnen beschriebenen Beispiele wirklich Geschäftslogik sind. Die von Ihnen beschriebenen Beispiele sind Vorgänge, die auf dem System ausgeführt werden können. Auf diese Weise haben Sie dem Benutzer die Auswahlmöglichkeiten präsentiert, die möglicherweise den Eindruck erwecken, als würden Sie in der Ansicht Geschäftslogik ausführen.

Vom Standpunkt "Ansicht" aus werden nur InfoY oder InfoZ für das System bereitgestellt. Nur weil Ihre UI-Implementierung einige dynamische Aktualisierungen auf der Grundlage einer Operatorauswahl durchführt (dh InfoY oder InfoZ aktiviert), wird die Geschäftslogik für die Funktionalität nicht berücksichtigt. Es ist wirklich Umsetzungslogik zu sehen. Sie hätten dem Operator auch einfach die Wahl geben können, InfoY oder InfoZ ohne die gesamte Aktivierungssache einzugeben. Würden Sie es in diesem Zusammenhang immer noch als Geschäftslogik betrachten? Wenn nicht, gilt dies auch für das dynamische Aktivieren / Deaktivieren von Infofeldern.

Gleiches gilt für das Commit-Beispiel. Dies sind zwei separate Vorgänge, die das System benötigt, um ordnungsgemäß zu funktionieren. Ihre Ansicht muss in der Lage sein, die richtigen Aktionen einzuleiten, um die gewünschte Funktionalität auszuführen. Bedeutet das Wissen über die Verwendung Ihres Systems, dass die Geschäftslogik durchläuft? Ich kann sehen, wie jemand Ja sagt, aber wenn Sie so glauben, dann ist die Realität, dass es keine Trennung der Geschäftslogik von irgendetwas gibt. Sie müssen wissen, was das System tut / mit dem es arbeitet, um etwas Sinnvolles zu erreichen. Andernfalls wäre es ein Kinderspiel, eine einzige generische Ansicht und einen Controller zu erstellen, die mit jeder denkbaren MVC-Anwendung kompatibel sind. Was wir wissen, ist unmöglich.

Unterm Strich ist Ihre Definition der Geschäftslogik nicht die gleiche wie die anderer.

Dunk
quelle
1

Ich arbeite so (Struts2 + Hibernate):

My Struts Actions ist nur für die Anzeige von Informationen im Webbrowser verantwortlich. Nicht denken.

Benutzer -> Aktion -> Dienst -> Repository -> Datenzugriff

Oder:

Ich möchte sehen -> wie man sieht -> was zu tun ist -> wie man kommt -> wo man kommt

Also, in der ersten Ebene (der Ansicht) habe ich etwas wie:

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";
}

Wie Sie sehen, meine "Sicht" nicht denken. Es fragt nach einem Dienst (zum Verwalten von Kursen) für einen bestimmten Kurs. Dieser Service kann noch vieles mehr, wie Berichte, Suchanfragen und so weiter. Das Ergebnis ist immer eine Liste oder ein bestimmtes Objekt (wie im Beispiel). Die Services sind die eigentliche Maschine, wenden Regeln an und greifen auf das Repository zu (um die Daten zu verwalten).

Wenn ich also meine Dienste, Repositorys und DAOS in verschiedene Bibliotheken lege, kann ich sie sogar in einem textbasierten Programm oder in einem Windows-basierten Desktopsystem verwenden, ohne dass sich etwas ändert.

Der Dienst weiß, was zu tun ist, weiß aber nicht, wie zu zeigen ist. Die Ansicht kann zeigen, weiß aber nicht, was zu tun ist. Dasselbe gilt für Service / Repository: Der Service sendet und fordert die Daten an, weiß jedoch nicht, wo sich die Daten befinden und wie sie zu entnehmen sind. Das Repository "bildet" die Rohdaten, um Objekte zu erstellen, mit denen der Service arbeiten kann.

Das Repository weiß jedoch nichts über die Datenbank. Die Art der Datenbank (MySQL, PostgreSQL, ...) betrifft DAO.

Sie können das DAO ändern, wenn Sie die Datenbank ändern möchten, und es darf sich nicht auf die oberen Ebenen auswirken. Sie können das Repository ändern, wenn Sie Ihre Datenverwaltung aktualisieren möchten, dies darf jedoch keine Auswirkungen auf das DAO und die oberen Ebenen haben. Sie können die Dienste ändern, wenn Sie Ihre Logik ändern möchten, dies darf jedoch nicht mit den darüber oder darunter liegenden Ebenen zu tun haben.

Und Sie können alles in der Ansicht ändern, auch die Technologie (Web, Desktop, Text), aber dies darf nicht bedeuten, dass Sie etwas darunter berühren.

Die Geschäftslogik lautet Service. Aber wie man damit interagiert, ist zu sehen. Welche Schaltfläche soll jetzt angezeigt werden? Kann der Benutzer diesen Link sehen? Denken Sie, Ihr System ist ein konsolenbasiertes Programm: Sie müssen ablehnen, wenn der falsche Benutzer ihn auswählt #> myprogram -CourseService -option=getCourse -idCourse=234oder anhält, um die Tasten zum Schreiben dieses Befehls zu drücken?

In webbasierten Systemen (Struts + JavaEE) habe ich ein separates GUI-Controller-Paket. In der Ansicht Aktion gebe ich dem angemeldeten Benutzer und die Klasse gibt mir die Schaltflächen (oder ein beliebiges von mir gewünschtes Oberflächenelement).

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

Und

private List<ActionButton> actionButtons;

Denken Sie daran, dies von den Diensten fernzuhalten. Das ist VIEW-Zeug. Behalten Sie es in den Struts-Aktionen bei. Alle Schnittstelleninteraktionen müssen vollständig vom tatsächlichen Geschäftscode getrennt sein. Wenn Sie also Ihr System portieren, ist es einfach zu schneiden, was Sie nicht mehr benötigen.

Magno C
quelle
1

In den meisten Fällen gibt es Probleme wie "Wenn der Benutzer die Option x ausgewählt hat, muss die Anwendung es ihm ermöglichen, Informationen für y einzugeben. Wenn nicht, sollte er Informationen für z eingeben."

Das ist Logik für das Modell, nicht die Sichtweise. Es kann sich um ein "Ansichtsmodell" handeln, das speziell zur Unterstützung der Benutzeroberfläche erstellt wurde, es handelt sich jedoch weiterhin um eine Modelllogik. Die Kontrollsequenz ist:

  • Der Controller hängt einen Handler für Ansichtsereignisse an
  • View fügt einen Handler für Modellereignisse hinzu
  • Der Benutzer wählt die Option X aus.
  • Die Ansicht löst ein Ereignis "Option X ausgewählt" aus
  • Controller empfängt das Ereignis und ruft model.selectOptionX () auf
  • Das Modell löst ein Ereignis "Modellstatus geändert" aus
  • Die Ansicht empfängt das vom Modell geänderte Ereignis und aktualisiert die Ansicht so, dass sie dem neuen Status entspricht: 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 ------| Dies ist das klassische MVC-Muster. Es ist möglich, die Modelllogik unabhängig von der Benutzeroberfläche vollständig zu testen. Der Controller und die Ansicht sind sehr dünn und einfach zu testen.

=== Als Antwort auf Dunk ===

Das Modell in einem UI-MVC-Muster ist (normalerweise) kein Geschäftsobjektmodell. Es ist nur das Modell für den UI-Status. In einer Desktop-Anwendung kann es Verweise auf mehrere Geschäftsmodelle enthalten. In einer Web 2.0-Anwendung ist es eine Javascript-Klasse, die den UI-Status enthält und über AJAX mit dem Server kommuniziert. Es ist sehr wichtig, in der Lage zu sein, Hands-Off-Unit-Tests des UI-Statusmodells zu schreiben, da dort die meisten UI-Fehler gefunden werden. Die Ansicht und Steuerung sollten sehr dünne Anschlüsse sein.

Kevin Cline
quelle
1
Ich denke, es läuft alles auf das hinaus, was Sie für die Definition von MVC halten. Diese Version hält definitiv an einer sehr, sehr strengen Interpretation von MVC fest. Das Problem ist, dass diese strikte Interpretation im wirklichen Leben selten ein nützliches oder wartbares System darstellt. Grund dafür ist, dass Sie das Modell fast jedes Mal ändern müssen, wenn Sie ein neues Element der Benutzeroberfläche oder eine neue Art, etwas zu tun, finden. Das Modell wird dann mit nutzlosen Eigenschaften überfüllt, die nur für die Benutzeroberfläche relevant sind. Diese haben nichts mit der Anwendung zu tun, die Sie erstellen möchten, sondern nur mit der Art und Weise, wie Sie dem Bediener Daten präsentieren möchten. SCHLECHT!
Eintauchen
Kevin, bitte tragen Sie Ihre Antworten hier in das Kommentarfeld ein, damit wir Ihnen problemlos antworten können. Ich stimme mit Ihnen ein. Es ist nicht möglich, Schnittstelleninformationen (UI) ohne irgendeine Struktur zu pflegen, aber die "MODEL" -Nomenklatur kann verwirrend sein. Ich bevorzuge es, UI-Inhalte in einem anderen austauschbaren Paket zu verwalten, um einfach zu tun, wovon @Dunk spricht. Siehe meine Antwort.
Magno C
@MagnoC: Ich habe die Antwort von Dunk bearbeitet, weil ich dachte, dass der hinzugefügte Text die Antwort verbessert. Darum geht es auf der Website: Fragen und Antworten. Modell ist ein ziemlich allgemeiner Begriff, und im MVC-Muster bedeutet dies "UI-Statusmodell".
Kevin Cline
0

Eine Geschäftslogik ähnelt eher einer If X then return InfoType.Y, dann zeigt die Benutzeroberfläche Felder basierend auf dem von der Domäne zurückgegebenen Ergebnis an.

// 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

Wenn die Benutzeroberfläche eine Geschäftslogik erfordert, delegieren Sie die Auswahl an die Domäne. Die Benutzeroberfläche wird einfach auf die Entscheidung reagieren.

Yorro
quelle
0

Wenn der Benutzer die Option x ausgewählt hat, muss die Anwendung ihm die Eingabe von Informationen für y ermöglichen. Wenn nicht, muss er Informationen für z "bereitstellen.

Es gibt Eingaben, die bedingt auf erforderlichen Werten basieren. In den meisten GUI-Umgebungen gibt es viele Möglichkeiten, wie Eingaben behandelt werden sollen, insbesondere das Timing. Die ausgewählte Option (in diesem Fall x) muss verarbeitet werden. Senden Sie sie an die Steuerung. Senden Sie es, wenn der Benutzer das Eingabefeld verlässt. Warten Sie, bis sie auf ein anderes Objekt klicken oder auf Speichern klicken. Für die Geschäftslogik spielt das keine Rolle. Auf die eine oder andere Weise trifft der Controller eine Entscheidung und muss der Ansicht mitteilen, "y ist erforderlich".

Wie die Sicht dies interpretiert oder implementiert, spielt aus Sicht der Geschäftslogik keine Rolle. Machen Sie ein Pflichtfeld. Nehmen Sie ein Pop-up oder schießen Sie von einer Kanone ab und fordern Sie den Benutzer auf, y einzutreten, oder seien Sie nur stur und lassen Sie den armen Benutzer nichts tun, bis sie dies herausgefunden hat.

Denken Sie nur daran, dass dies alles möglicherweise darauf zurückzuführen ist, dass der Controller versucht hat, einen Wert für ein erforderliches Feld in der Datenbank zu speichern, und lediglich auf einen Datenbankfehler reagiert hat. Für die Sicht ist es egal.

So etwas wie ein erforderlicher oder begrenzter Wert für eine Eingabe kann an vielen Stellen verarbeitet werden. Wenn Sie es "nur" in der Ansicht ansprechen, wird dies von vielen Entwicklern als Problem angesehen, wenn es mehrere Benutzeroberflächen geben kann. Aus diesem Grund kann Geschäftslogik ohne große Benutzerschnittstelle oder sogar ohne Datenbank erstellt und getestet werden. Sie müssen nicht einmal eine Website haben.

JeffO
quelle