../engineering.html ../qjsn/qjsn.html


Model View Controller Pattern

Das Model View Controller (MVC) ist eine Art Kochrezept bzw. Muster, wie man seine Aufgabenstellung umsetzen sollte. Das Prinzip ist dabei Entkopplung von GUI und Geschäftslogik bzw. Abstraktion ähnlich wie bei Objektorientierung. Häufig benötigt man für eine Applikation irgendwelche Daten, die dann in irgendeiner Form aufbereitet dem Anwender präsentiert werden. Der Anwender kann dann irgendwelche Handlungsaktionen mit Hilfe der GUI vornehmen und so bestimmte Aufgaben umsetzen. Früher wurden diese Lösungen monolithisch implementiert, so dass Geschäftslogik, Daten und GUI unter Umständen nicht klar voneinander getrennt waren.

MVC bietet ein Schema oder Muster an, wie man am besten objektorientiert die Aufgabenstellung umsetzt. Es wird die Gesamtfunktionalität nach Model( Daten ), View ( GUI ) und Controller strukturiert.


Gründe für das Model View Controller Pattern:

  • Entkopplung von Geschäftslogik und GUI
  • Erhöht Wartbarkeit / Datenabstraktion / klare Arbeitsteilung
  • Bessere Wiedervervendbarkeit / Objektorientierung => Synergie
  • (bei kleineren Anwendungen mag der Aufwand übertrieben sein)

  • Durch die klare Entkopplung, kann man das View auch für ein anderes Model also für andere Daten einsetzen. Die Geschäftslogik kann weiterentwickelt werden unabhängig von der GUI ( View ). Ein View für eine bestimmte Geschäftslogik läßt sich mit geringem Aufwand durch ein anderes View ersetzen, so dass man für bestimmte Daten ( Model ) verschiedene Repräsentationen leicht realisieren kann.

    Das Vorgehen ist dabei mehr wie eine Softwarefirma zu sehen, d.h. man muss mehr in Komponenten denken, die man dem Kunden als Bausteine / Komponenten anbieten kann, die er dann nach seinen eigenen Vorstellungen einbaut. So wie z.B. die Qt Library, wo nicht feststeht, was die Firma XY mit dem QTreeView konkret implementieren will.

    Model

  • Diese Komponente beinhaltet das Datenmodell der Anwendung
  • Diese Komponente hat keinerlei Kenntnis über die Implementierung der Views (ein oder mehrere)
  • Datenänderung löst Nachricht/Signal aus, so dass ggfs. die Views ihren internen Zustand ändern
  • View

  • Diese Komponente stellt die Präsentationsschicht dar, d.h. die GUI
  • View meldet sich beim Model zur Benachrichtigung an
  • Views (kann auch nur eins sein) bekommen Nachricht / Signal vom Model und ändern dann ihren internen Zustand
  • Controller

  • Diese Komponente steuert die Präsentationsschicht ( View ) und nimmt von dieser Aktionen entgegen
  • Model und View kommunizieren (Nachrichten/Signale/Daten) nicht direkt miteinander, sondern über den Controller
  • Beispiel

    Der Benutzer / Anwender sitzt vor seinem Bildschirm:

    Das VIEW zeigt ihm einen ACCEPT-Button und eine PROGRESSBAR an. Der Benutzer hat z.B. den BUTTON zur Bestätigung gedrückt, woraufhin das PROGRESSBAR-GUI-ELEMENT auf 60% gesprungen ist und entsprechend hochzählt. Der ACCEPT-BUTTON würde z.B. als nächstes Ereignis verschwinden und die PROGRESSBAR würde bei einem erfolgreichen Laden bei 100% ebenfalls verschwinden...

    Nochmal zurück zur Handlungsaktion "ACCEPT-BUTON betätigt" durch den Anwender:

    Das VIEW registriert diese Aktion als Signal / Nachricht, gibt diese Informmation an den CONTROLLER weiter. Dieser sendet dem MODEL die Information, z.B. Laden aus der Datenbank oder einer anderen Datenquelle fortsetzen und Ladezustand in Prozent an CONTROLLER rückmelden. Der CONNTROLLER reicht diese Information dann an das VIEW weiter, so dass die PROGRESSBAR die entsprechende Zustandsänderung auf 60% vornimmt.

    Fazit:

    Das VIEW muss vom MODEL nicht wissen, mit welcher Datenquelle es gerade arbeitet und auch nichts über die interne Implementierung kennen. Durch diese Abstraktion läßt sich dass VIEW für recht beliebige Vorgänge einsetzen, wo der aktuelle Zustand (Fortschrittsanzeige) dem Anwender in Prozent dargestellt wird.

    Entwurfsmuster Model View Controller

  • Views: UI-Design / Präsentationsschicht ( 1 oder mehrere )
  • Model: Datenmodell/Geschäftslogik
  • Controller: Model und View kommunizieren über den Controller
  • Entwurfsmuster Model View Presenter

  • View: UI-Design / Präsentationsschicht ( 1 oder mehrere )
  • Model: Datenmodell/Geschäftslogik
  • Presenter: Model und View kommunizieren über den Presenter
  • Entwurfsmuster Model View View Model

  • Views: UI-Design ( 1 oder mehrere )
  • View Model: UI-Logik
  • Model: Datenmodell/Geschäftslogik
  • MVVM erlaubt eine bessere Trennung von User-Interface-Design und
    User-Interface-Logik (Abhängigkeiten zwischen Benutzeroberfläche und
    Geschäftslogik auf ein Minimum reduzieren)
  • In .NET-Frameworks (WPF, Autor: John Grossmann 2005)
    recht beliebtes Entwurfsmuster
  • Für Plattform-unabhängige Entwicklung interessant: Model
    und ViewModel sollten portable realisiert werden, die Views
    sind natürlich plattformabhänig bzw. -spezifisch.
  • Beispiel Chart aus Qt5.2.0 examples\widgets\itemviews\chart (Quellcode siehe http://www.qt.io)


    Die Funktionalität für das MVC Beispiel findet sich in folgenden Dateien:

  • CONTROLLER + MODEL: mainwindow.{h,cpp}
  • VIEW: pieview.{h,cpp}
  • Das VIEW realisiert die Funktionalität für die "Torten"-View

  • Klasse PieView ist abgeleitet von QAbstractItemView

    folgende protected slots:


  • void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles = QVector());
  • void rowsInserted(const QModelIndex &parent, int start, int end);
  • void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end);

  • Klasse MainWindow ist abgeleitet von QMainWindow

    folgende private methods:

  • void setupModel();
  • void setupViews();

  • relevante private members:

  • QAbstractItemModel    *model;
  • QAbstractItemView      *pieChart;
  • QItemSelectionModel  *selectionModel;
  • Auszug aus Qt5.2 examples\widgets\itemviews\chart\mainwindow.cpp (Quellcode siehe http://www.qt.io)


    Zum Code:

    Es gibt hier in diesem Beispiel zwei VIEWS: Neben dem PieView wird noch ein QTableView verwendet!

    Deshalb wird in der Zeile 89 und 90, erst dem table und dann dem pieChart mit der Methode setModel das Model zugeordnet.

    QItemSelectionModel in Zeile 92 ist mit dem Model verknüpft und wird bei den Views mit der Methode setSelectionModel angemeldet.

    Aus meiner Sicht ist die Methode setupViews eher als setupController oder setupMVC zu sehen, da hier die "Zusammenschaltung" von MODEL, VIEW und CONTROLLER erfolgt.


    Nebenbei, die Befüllung des Models mit Daten erfolgt mit der Methode setData, zu finden in MainWindow::openFile(...).


    Überladene Methoden aus QAbstractItemView für PieView:

    void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles = QVector());

    siehe auch: ..Src\qtbase\src\corelib\itemmodels\qabstractitemmodel.cpp, wo die überladene Funktionalität von dataChanged, rowsInserted und rowsAboutToBeRemoved herkommt ...

    Für das Chart-Beispiel wurden die Methoden wie folgt überladen:



    =end of page=