Announcement

Collapse
No announcement yet.

Model View Presenter-Muster

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Model View Presenter-Muster

    [edit=gfoidl] Abgetrennt von http://entwickler-forum.de/showthread.php?t=56972 [/edit]

    Hallo,

    danke für die Anregungen und Hinweise.

    Die Wortwahl Controller gefällt mir besser als Presenter, da ich mit diesem den View assoziere.

    GenericDelegate entnahm ich per Copy & Paste ohne gross nachgedacht zu haben. In der Anwendung von Generics habe ich bisher noch keine Praxiserfahrung, also erklären kann ich es auch nicht

    Mir gefällt das neue Konzept des Parallel.For & Co. und freue mich auf eine ausgereifte Anwendung in 4.0. Das ich mich nun tiefer eingelesen habe, ist auch vollkommen in Ordnung.

    Die Lösung lag übrigens im Controller (oder Presenter):

    Code:
            delegate void CalculateDelegate();
            void view_Calculate(object sender, EventArgs e)
            {
                CalculateDelegate calcDel = new CalculateDelegate(Calculate);
                calcDel.BeginInvoke(null, null);  
            }
            void Calculate()
            {
                System.Threading.Parallel.For(0, 5, delegate(int i)
                {
                    view.UpdateLabelText(i.ToString());
                });
            }
    MFG
    sci
    Zuletzt editiert von gfoidl; 21.08.2009, 13:39.

  • #2
    Die Wortwahl Controller gefällt mir besser als Presenter, da ich mit diesem den View assoziere.
    Entspricht aber nicht der Wortwahl des Musters*.

    * Das es ein Muster ist kann es jeder interpretieren/verwenden wie er will. Ein Muster soll nur eine Inspiration für die eigenen Verwendung sein. Insofern kannst du das bezeichnen wie du willst. Wenn aber in einem Team gearbeitet wird empfiehlt sich die Verwendung der korrekten Terminologie.


    mfG Gü
    "Any fool can write code that a computer can understand. Good programmers write code that humans can understand". - Martin Fowler

    Comment


    • #3
      Kleine Frage am Rande... erzeugt nicht eigentlich der View selbst seinen Presenter in seinem Konstruktor?

      [highlight=c#]
      public class View
      {
      MyPresenter _presenter;

      public View()
      {
      _presenter = new MyPresenter(this);
      }
      }[/highlight]

      Comment


      • #4
        erzeugt nicht eigentlich der View selbst seinen Presenter in seinem Konstruktor?
        Von diesen Mustern gibt es so viele Varianten und Abwandlungen dass die Erstellung der Instanzen irgendwo sein kann.
        Ich erzeuge die Instanzen aber so wie von dir gezeigt - meist übergebe ich dem Konstruktor des Presenter noch eine Instanz des Services der die Daten liefert (Depency Injection).


        mfG Gü
        "Any fool can write code that a computer can understand. Good programmers write code that humans can understand". - Martin Fowler

        Comment


        • #5
          Frage von fanderlf (per PN):

          Hallo,

          Jetzt muss ich nochmal nerven. Machst Du das mit Dependency Injection auch in Windows Forms Anwendungen. Also konkret auf das MVP Pattern bezogen.

          Woher weiss der Service dann welchen Datensatz er anzeigen soll?
          Übergibst Du dem View eine Id des Datensatzes die er anzeigen soll, welche sich dann der Presenter holt und die Daten aus dem Service zieht?
          Ich habe das derzeit so gelöst, dass ich meinem View ein Object übergeben kann. Wenn ich das setze merkt der Presenter das und baut den View neu auf.

          Dependency Injection hab ich mir nicht gleich zugetraut, da ich noch relativ neu auf dem gibt Domain Modell/OOP bin. Und das ist ja doch ein relativ komplexes Thema.

          Vielen Dank für Hilfe!!!!

          Gruß
          Florian
          "Any fool can write code that a computer can understand. Good programmers write code that humans can understand". - Martin Fowler

          Comment


          • #6
            Hallo,

            Depency Injection ist ein Muster mit dem Abhängigkeiten gelöst (eigentlich verschoben) werden.

            Beispiel (ohne Verwendung von Depency Injection):
            [highlight=c#]
            namespace ConsoleApplication1
            {
            class Program
            {
            static void Main(string[] args)
            {
            Auto auto = new Auto();
            auto.Beschleunigen();
            }
            }

            public class Auto
            {
            private Motor _motor = new Motor();

            public void Beschleunigen()
            {
            _motor.ErhöheDrehmoment();
            }
            }

            public class Motor
            {
            public void ErhöheDrehmoment()
            { }
            }
            }
            [/highlight]
            Darin existiert eine Abhängigkeit des Autos vom Motor. Was ist wenn es mehrere Motoren zur Auswahl gibt? Probleme.
            Durch Verwendung von Depency Injection kann diese Abhängigkeit gelöst werden.
            [highlight=c#]
            namespace ConsoleApplication1
            {
            class Program
            {
            static void Main(string[] args)
            {
            Motor motor = new Motor();
            Auto auto = new Auto(motor);
            auto.Beschleunigen();
            }
            }

            public class Auto
            {
            private Motor _motor;

            public Auto(Motor motor)
            {
            _motor = motor;
            }

            ...
            }

            ...
            }
            [/highlight]
            Es hat sich fast nichts geändert im Code. Die Änderungen habe aber ein große Auswirkung. Das Auto hat keine Abhängigkeit mehr vom Motor denn der konkrete Motor wird dem Auto im Konstruktor mitgegeben (Constructor injection). Die Abhängigkeit wird "eingespritzt" -> daher die Bezeichnung Depency injection. Genauso wäre es möglich die konkrete Instanz des Motors per Eigenschaft (Setter injection) dem Auto mitzuteilen. Es gibt noch eine dritte Variante aber diese lasse ich hier außen vor.
            Wirklich Sinn macht das ganze nur wenn der Motor als (abstrakte) Basisklasse weiterer Motoren dient von denen dann die konkrete Implementierung dem Auto übergeben wird. Mit Schnittstellen (IMotor) funktioniert das natürlich auch.
            Das Problem der Abhängigkeiten hat sich jetzt vom Auto zur Main-Methode verlagert - irgendwo muss es ja gelöst werden. Treibt man das Spiel weiter kann die Abhängigkeit in einer Konfigurationsdatei landen und die verschiedenen Motoren können ohne erneutes Kompilieren gewählt werden. Für die Erstellung der Instanzen aus der Konfigurationsdatei gibt es Implementierungen wie ServiceLocator oder Microkernel. Hört sich schlimm an ist es aber gar nicht (minimal 5 Zeilen Code, so circa).


            Machst Du das mit Dependency Injection auch in Windows Forms Anwendungen.
            Ja, warum auch nicht. Sonst ist es meiner Meinung nach gar nicht möglich MVP umzusetzen.

            Woher weiss der Service dann welchen Datensatz er anzeigen soll?
            Der Service zeigt keine Daten an, das macht die View. Der Service liefert die Daten zum Presenter.
            Dem Presenter wird im Konstruktor die Instanz der View mitgeteilt und die konkrete Instanz des Service. Klickt der User in der View zB auf Filtern so wird benachrichtigt die View ihrren Presenter (entweder per direkten Methodenaufruf oder per Ereignis - wobei ich Ereignisse vorziehe denn diese können in der IView-Schnittstelle definiert werden) dass gefiltert werden soll. Der Presenter holt sich dann über die Eigenschaften der View die Wert die er beötigt und ruft die Filter-Methode des Service auf und bekommt die Daten vom Service geliefert. Danach setzt der Presenter die Eigenschaften der View um diese gefilterten Daten anzuzeigen.
            Diese Daten werden gemeinhin als Model geschlossen. Somit schließt sich der "Kreis" im Model-View-Presenter-Muster.

            Dependency Injection hab ich mir nicht gleich zugetraut, da ich noch relativ neu auf dem gibt Domain Modell/OOP bin. Und das ist ja doch ein relativ komplexes Thema.
            Es hört sich nur komplex an ist es aber gar nicht. Für mich ist es eher so dass ein weiteres Kind einen Namen bekommen musste. Damit meine ich dass jeder vernüftige Entwickler irgendwann Problem mit Abhängigkeiten hat und diese lösen versucht. Die Lösung führt dann fast zwangsweise zu einem Muster das wie im obigen Beispiel dargestellt umgesetzt wird. Dass Martin Fowler das als Depency Injection bezeichnet hat und publiziert hat ist eine andere Sache.
            Wichtig dabei ist nur dass Schnittstellen und (abstrakte) Basisklassen im Hinterkopf die Arbeit erleichtern anstatt sich auf ein Muster zu verstarren. Wenn das Werkzeug (in diesem Fall C#) verstanden ist dann kommen die Lösungen von alleine ohne dass man suchen muss welcher Muster passen könnte. Das soll aber nicht heißen dass Muster für die Fische sind sondern sie sollen als "Inspiration" für eigene Lösungen verstanden werden.

            Ich hab auf meinem Space eine Demo-Anwendung hochgeladen die eine Variante des MVP-Musters zeigt welche ich gerne als Referenz für meine Implementierungen verwende (kann aber sicher noch verbessert/verändert) werden.
            Es zeigt eine primitive Benutzerverwaltung mit mehreren Fenstern (View nur als WinUI).


            mfG Gü
            "Any fool can write code that a computer can understand. Good programmers write code that humans can understand". - Martin Fowler

            Comment


            • #7
              Also dependency injection hab ich soweit schon einigermaßen verstanden. Aber die MVP beispiele sind immer so ausgelegt, dass sie eine Menge an Daten anzeigen. Ich habe bei mir in der Arbeit ein Tool in dem ich immer genau ein Element darstellen will. Übergebe ich dann dem View im Konstruktor oder per Property die Id des Elements was ich darstellen will? Der Presenter kann sich dann diese Id holen und aus dem Datenservice das gewünschte Element auswählen.
              So wäre der View auch komplett vom Datenservice entkoppelt. Ich hatte mir das schon mal überlegt...

              Konkret handelt es es um einen Kabelbaum. Der hat eine gewisse Anzahl an Steckern und Kabeln dazwischen. Nun habe ich eine Diagramkomponente... für jedes Kabel und für jeden Stecker gibt es ein Kästchen mit Eingängen und Ausgängen die auch noch unsichtbar geschalten werden können, wenn sie nicht verbunden sind.

              Mein Ansatz war jetzt:

              Es gibt eine View für den gesamten KabelBaum. Diesem View kann ich dann weitere (kleinere) Views hinzufügen die den Kästchen entsprechen. Für eine Verbindung gibt es auch eine View.

              Ist das der richtige Weg? Ich bin noch relativ neu in der Materie... und es fühlt sich auch noch immer noch relativ gut an

              Comment


              • #8
                Hallo,

                ohne allzu lange überlegt zu haben würde ich das so lösen (grober Entwurf):
                Die KabelbaumView feuert Ereignisse die der KabelbaumPresenter verarbeitet (wie bei jedem MVP). Für Stecker, etc. UserControls verwenden die der Presenter dem KabelbaumView hinzufügt (zu einer IList<ISteckerView>). Und so weiter...
                Also ein Presenter der mit der KabelbaumView kommuniziert. Somit weiß er auch was er anzeigen soll. Ich verstehe dein Problem nicht ganz.

                Es dabei auch nicht darum MVP 1:1 von einer Referenz nachzubilden sondern die Kernziele von MVP zu verwirklichen die wären:
                • Testbarkeit
                • Unabhängigkeit von der konkreten UI
                • Orthogonalität (dieser Punkt deckt eigentlich auch Punkt 2 ab).


                mfG Gü

                PS: Konnte nicht früher antworten da ich nich da war
                "Any fool can write code that a computer can understand. Good programmers write code that humans can understand". - Martin Fowler

                Comment


                • #9
                  ah super Genau so hab ichs auch implementiert. Ich wollte mich nur mal bei jemandem erkunden der das auch einsetzt. Hier in der Firma werde ich momentan für diese Vorgehensweise leider nur belächelt... aber das wird sich noch ändern

                  Achja... für mich gabs noch ein weiteres Kernziel des MVP. Wenn ich das alles in eine Form reinverwurste, dann wird das irgendwie alles immer nichts. Mit MVP kann man das alles sehr schön trennen und ist deswegen sehr flexibel.

                  Comment


                  • #10
                    Achja... für mich gabs noch ein weiteres Kernziel des MVP. Wenn ich das alles in eine Form reinverwurste, dann wird das irgendwie alles immer nichts. Mit MVP kann man das alles sehr schön trennen und ist deswegen sehr flexibel.
                    Das wird mit dem Begriff Orthogonalität beschrieben.


                    ah super Genau so hab ichs auch implementiert. Ich wollte mich nur mal bei jemandem erkunden der das auch einsetzt. Hier in der Firma werde ich momentan für diese Vorgehensweise leider nur belächelt... aber das wird sich noch ändern
                    Wer zuletzt lacht...
                    Nur weiter so

                    mfG Gü
                    "Any fool can write code that a computer can understand. Good programmers write code that humans can understand". - Martin Fowler

                    Comment


                    • #11
                      Wer zuletzt lacht...
                      Nur weiter so
                      @fanderlf : Da solltest du vorsichtig sein und versuchen die Kollegen ins Boot zu holen. Aus Erfahrung kann ich dir sagen das eine nicht akzeptierte Architektur im nachhinein, wenn Sie von deinen Kollegen aus Unwissenheit ~kaputtgewartet~ wird, üblicherweise mehr Probleme macht als ein System ohne erkennbare Architektur. Und wer ist am Ende Schuld .... Der Architekt mit seiner Architektur.

                      Architektur ist wichtig. Ein Konsens in einem Team wie entwickelt wird aber noch viel wichtiger!

                      Comment


                      • #12
                        Das ist mir klar... ich versuche ja auch das ganze hier etwas voranzutreiben. Konsens im Team gibts bei uns leider nicht. Das ist ja das wo ich gerade versuche meinen Chef etwas sensibel zu machen.
                        Die Abteilung war auch unsprünglich keine Softwareentwicklungsabteilung. Alles hat mit kleinen Geschichten angefangen und ist dann etwas größer geworden.
                        Es sind alles noch 1-Mann Projekte, allerdings macht wirklich jeder in dieser Abteilung was er will. Wir haben auch ganz viele unterschiedliche Bereiche. Das geht von Messdatenauswertung über µC Programmierung in C und Assembler bis hin zu Datenbankgeschichten.
                        Allerdings gibt es überhaupt keinen Konsens wie denn die Programme auszusehen haben. Leute die eigentlich gar keine Ahnung von Software Architektur haben werden dann einfach mal eben damit betraut die komplette Software im Alleingang zu designen.
                        Ich versuche hier gerade eine Basis zu schaffen, damit wir alle endlich mal vernünftige Programme schreiben können. Die auch von anderen gewartet werden können. Momentan läuft softwareentwicklung nämlich so:

                        1. Chef kommt wir brauchen eine neue Software
                        2. Wir öffnen die Programmierumgebung
                        3. Wir öffnen den Fensterdesigner
                        4. Wir klicken einen button hinein
                        5. Wir hinterlegen die komplette Programmlogik hinter diesem einen Fenster direkt im EventHandler des Buttons. Vom Datenbankzugriff über Business Reglern (diese werden üblicherweise über Steuerelementeigenschaften implementiert -> Readonly auf einer Textbox) bis hin zu Gui Code

                        SoC wird höchstens dadurch erreicht, dass man mal ein neues Fenster aufmacht und das wars dann.
                        Natürlich explodiert sowas in etwas größeren Projekten irgendwann, wenn dann mal bei den ganzen Seiteneffekten die eine Änderung hat gar keiner mehr durchblickt.

                        Da es sowieso keine Struktur gibt versuche ich einfach mal einen Standard zu finden. Ich versuche auch die Kollegen davon zu überzeugen, dass das die richtige herangehensweise ist. Allerdings muss man dafür auch erstmal die Vorzüge beweisen können. Auf den ersten Blick sieht das erstmal nach sooooooooooooo viel mehr Arbeit aus.

                        Ich könnte jetzt hier noch stundenlang schreiben... aber ich muss aufhören, sonst muss ich mich nur wieder dermaßen ärgern -.- es wird noch nicht mal wirklich geschätzt, dass sich jemand Gedanken um die Softwarequalität macht.

                        Grüße
                        Florian

                        Comment


                        • #13
                          Mach dem Chef mal den Vorschlag dass mit einer kleinen Präsentation die Vorteile von OOP näher bringen willst und im Zuge dessen deine Standards zum Firmen-Standard werden. Ich glaub das wäre einen Versuch wert.

                          Aus dem http://openbook.galileocomputing.de/oop/ kannst du exemplarische Diskussionen entnehmen und als Richtlinie für deine Präsentation nehmen.

                          Für den Chef dreht sich alles um Zeit + Geld. Stell einfache Rechnungen an die zeigen dass sich guter Entwurf sowohl in Zeit und Geld positiv bemerkbar machen. Weihe auch die Mitarbeiter ein denn sie sollten nicht übergangen werden - dann würde es nie etwas.


                          mfG Gü
                          "Any fool can write code that a computer can understand. Good programmers write code that humans can understand". - Martin Fowler

                          Comment


                          • #14
                            Wenn ich dir jetzt sage dass mein Chef genau dieses Buch runtergeladen und aufs Netz gelegt hat, dann wirst Du bestimmt vom Stuhl fallen vor lachen, oder?
                            Ich werd mir diese Diskussion aber auf jeden Fall mal anschauen. Vielen Dank für den Tip...

                            Ich glaube mein Chef denkt: Dieses OOP Zeug hört sich zwar nett an ist aber in der Praxis nicht zu gebrauchen. Ganz zu schweigen von dem ganzen Overhead den man programmiert. Von TDD und ähnlichen Methoden ganz zu schweigen.
                            Ich glaub Chefs muss man das erst beweisen dass das ganze Thema funktioniert. Ich glaube nach wie vor daran und in großen Projekten geht es ja gar nicht anders. Aber ich versuche schon das Thema meinen Kollegen näher zu bringen. Es muss einfach etwas standard her... nicht umsonst schreiben wir fast jede Software neu, sobald der Entwickler weg ist und keiner mehr bei der Software durchblickt. Gott sei dank programmieren wir "nur" firmeninterne Software. An Endkunden könnte man so etwas nicht ausliefern...

                            Gruß
                            Florian

                            Comment


                            • #15
                              Wenn ich dir jetzt sage dass mein Chef genau dieses Buch runtergeladen und aufs Netz gelegt hat, dann wirst Du bestimmt vom Stuhl fallen vor lachen, oder?
                              Ja - das ist cool

                              Ich habe auch sehr lange imperativ mit Fortran programmiert. Einer der größten Vorteile von OOP ist von "außen betrachtet" dass die Realität besser modelliert werden kann. Dies ist mit imperativer Programmierung fast nicht zu bewerkstelligen.

                              Wenn ich auf das obige Auto-Beispiel zurückgreifen wird dies schon bemerkbar. Reale Objekte (Auto hat einen Motor) können auf Code-Objekte (fast) 1:1 umgemünzt werden. Mit imperativer Programmierung müssen dazu eine Unmenge Prozeduren und Module geschrieben werden um die Realität nachbilden zu können.
                              Aus diesem (für mich größten Vorteil) lassen sich allen anderen Vorteile von OOP ableiten:
                              • die verschiedenen Klassen können unabhängig voneinander entwickelt werden und das spart Zeit
                              • die verschiedenen Klassen können einfacher wiedervewendet werden und das spart Zeit + Geld
                              • der Code ist besser testbar und das kostet einmalig ein wenig Zeit und bringt eine große Kosten- und Zeitersparnis da die Fehler teurer sind je später sie entdeckt werden
                              • .... (nicht endend)


                              So oder so ähnlich würde ich das den Kollegen beibringen (wie bei kleinen Kindern halt ).


                              mfG Gü
                              "Any fool can write code that a computer can understand. Good programmers write code that humans can understand". - Martin Fowler

                              Comment

                              Working...
                              X