Daten bearbeiten, welche sich in abgeleiteter Klasse befinden


  • Administrator

    @mogel,
    Schon mal etwas von Trennung von Daten, GUI und Logik gehört? Eine GUI-Komponente hat definitiv nichts in IFilter zu suchen.
    Was für ein Control soll da zurückgegeben werden? WinForms? WPF? Oder was eigenes? Vielleicht ein Konsolen-Control?

    Grüssli



  • Dravere schrieb:

    Schon mal etwas von Trennung von Daten, GUI und Logik gehört? Eine GUI-Komponente hat definitiv nichts in IFilter zu suchen.
    Was für ein Control soll da zurückgegeben werden? WinForms? WPF? Oder was eigenes? Vielleicht ein Konsolen-Control?

    wenn Du mir jetzt verräts wo ich das MVC zerstört habe ... ein Interface gehört bei mir zum Controler, welcher zwischen Model (Filterimplementierung) und View (Control) vermittelt


  • Administrator

    mogel schrieb:

    Dravere schrieb:

    Schon mal etwas von Trennung von Daten, GUI und Logik gehört? Eine GUI-Komponente hat definitiv nichts in IFilter zu suchen.
    Was für ein Control soll da zurückgegeben werden? WinForms? WPF? Oder was eigenes? Vielleicht ein Konsolen-Control?

    wenn Du mir jetzt verräts wo ich das MVC zerstört habe ... ein Interface gehört bei mir zum Controler, welcher zwischen Model (Filterimplementierung) und View (Control) vermittelt

    😕
    Was ist das denn für eine Ansicht von MVC? Damit bringt dir MVC ja rein gar nichts, weil du immer noch alles fest verkoppelt hast. Du kannst nicht einfach deine View austauschen und zum Beispiel von WinForms auf WPF wechseln, weil du die Filter (also Daten) fix mit der View verkoppelt hast. Und das sogar noch über die stärkste Verbindung überhaupt: Vererbung.

    Grüssli



  • lassen wir mal WPF weg - nutze ich nicht

    IFilter filter = something as IFilter;
    Control control = filter->GetConfigControl();
    

    ich sehe da nur eine Bindung - und zwar zwischen einem konkreten Filter und seiner konkrekten GUI für die Einstellungen


  • Administrator

    mogel schrieb:

    ich sehe da nur eine Bindung - und zwar zwischen einem konkreten Filter und seiner konkrekten GUI für die Einstellungen

    Genau, es ist eine Bindung, nämlich zwischen WinForms und IFilter . Was ist aber nun, wenn jemand IFilter nicht in WinForms anzeigen möchte, sondern in WPF? Oder vielleicht auf der Konsole eine Ausgabe machen möchte. Dann bist du völlig auf WinForms fixiert. Du hast die View eben nicht von den Daten getrennt, sondern völlig zusammengeschweisst. Das ist nicht der Sinn von MVC.

    Mit korrekten MVC kannst du IFilter dann ohne Probleme auch in WPF verwenden oder nur in einem Konsolenprogramm. Dann hast du eine View für WinForms, du hast eine View für WPF, du hast eine View für die Konsole, usw. usf.

    Grüssli



  • Was ist aber nun, wenn jemand IFilter nicht in WinForms anzeigen möchte, sondern in WPF?

    wie schon geschrieben - ich nutze WPF nicht und wolltes erstmal weg lassen ... es ging um grundsätzliche MVC Dinge

    public interface IFilter
    {
      bool Check(String arg);
      IFilterConfig GetConfigControl();
    }
    
    public interface IFilterConfig
    {
      bool OpenFilterConfig();
    }
    
    public class FormsFilterConfig : IFilterConfig
    {
    }
    
    public class WPFFilterConfig : IFilterConfig
    {
    }
    
    public class ConsoleFilterConfig : IFilterConfig
    {
    }
    

    Du musst irgendwo eine Bindung zwischen IFilter und der Konfiguration herstellen ... kannst Du auch in einer statischen Methode machen (was etwas mehr Pflege erfordert) - ist aber prinzipell egal ... es existiert dann aber immer eine feste Bindung zwischen einem konkreten Filter und einer konkreten Oberfläche

    selbst wenn wir nur bei Forms bleiben

    public interface IFilter
    {
      bool Check(String arg);
      Control GetConfigControl();
    }
    

    hier wird noch nicht mal ein Control instanziert welches sinnlos Speicher verschwendet ... nutzen kannst Du den Filter dennoch beliebig ... selbst die Darstellung der Config ist unabhängig vom Filter ... alternativ kannst Du das Ganze auch trennen

    public interface IFilterConfig
    {
      Control GetConfigControl();
    }
    
    public class MyFiler : IFilter, IFilterConfig
    {
    }
    

    egal wie Du es drehst und wendest ... über das C verbindest Du M & V


  • Administrator

    mogel schrieb:

    wie schon geschrieben - ich nutze WPF nicht und wolltes erstmal weg lassen ... es ging um grundsätzliche MVC Dinge

    Wenn du mal meinen Beitrag genau liest, rede ich auch über allgemeine MVC Dinge. Ob WPF, WinForms, Konsole oder sonstwas ist völlig egal, das sind nur Beispiele.

    mogel schrieb:

    Du musst irgendwo eine Bindung zwischen IFilter und der Konfiguration herstellen ... kannst Du auch in einer statischen Methode machen (was etwas mehr Pflege erfordert) - ist aber prinzipell egal ... es existiert dann aber immer eine feste Bindung zwischen einem konkreten Filter und einer konkreten Oberfläche

    Ja, aber die sollte die Filterklasse nicht beeinflussen. Du bindest alles mit Superkleber zusammen, statt es nur über Schnittstellen laufen zu lassen. IFilter sollte das Model sein und nichts über das View oder den Controller wissen.

    Also mal etwas mit Pseudo-Code verdeutlicht:

    public interface IFilterView
    {
      void Display(IFilter filter);
    }
    
    public class FilterWPFView : IFilterView { /* ... */ }
    
    public class FilterWinFormsView : IFilterView { /* ... */ }
    
    public class FilterConsoleView : IFilterView { /* ... */ }
    
    // ...
    
    IFilterView view = new FilterWPFView();
    view.Display(filter);
    

    IFilter hat somit keine Abhängigkeit zur View mehr. Ich kann IFilter in eine eigene DLL auslagern, welche keine Abhängigkeiten zur WPF oder WinForms DLL hat. Hier hast du eine deutlich stärkere Trennung von Daten und Ansicht.

    Vererbung ist immer die stärkste Verbindung, welche es gibt. Im allgemeinen sollte sie als letztes in Betracht gezogen werden.

    mogel schrieb:

    egal wie Du es drehst und wendest ... über das C verbindest Du M & V

    Wie ich schon mehrfach gesagt habe, geht es darum, wie man es verbindet. MVC war ja dazugedacht, dass man die Dinger eben stark entkoppelt. Da ist es nicht sehr sinnvoll, dies mit der stärksten Bindung, welche es gibt, wieder zusammenzukleben.

    Grüssli



  • IFilter sollte das Model sein und nichts über das View oder den Controller wissen.

    ich betrachte Interfaces als Bestandteil von C ... wärend Klassen zu M gehören ... wir haben hier also schon zwei Ansichten

    IFilterView view = new FilterWPFView();
    view.Display(filter);
    

    wenn ich jetzt einen eigenen Filter implementiere, zeigt mir Dein FilterWPFView Details meiner Klasse an?



  • mogel schrieb:

    ich betrachte Interfaces als Bestandteil von C ... wärend Klassen zu M gehören ... wir haben hier also schon zwei Ansichten

    Das hat wenig mit Ansichen zu tun, das was du betreibst widerspricht den Grundprinzipien von MVC, und sollte daher korrekterweise auch nicht so genannt werden.


  • Administrator

    mogel schrieb:

    ich betrachte Interfaces als Bestandteil von C ... wärend Klassen zu M gehören ... wir haben hier also schon zwei Ansichten

    Siehe Antwort von asc. Ich würde dir empfehlen, dich mit dieser Thematik nochmals auseinander zu setzen.

    mogel schrieb:

    IFilterView view = new FilterWPFView();
    view.Display(filter);
    

    wenn ich jetzt einen eigenen Filter implementiere, zeigt mir Dein FilterWPFView Details meiner Klasse an?

    Sofern sich dein Filter an die definierten Konventionen hält, sicher. Aber wer würde dir verbieten, ein eigenes View für deinen Filter zu schreiben, welches von IFilterView ableitet? Danach kannst du einfach diese View für deinen Filter verwenden.

    Ich persönlich erkläre es noch gerne an diesem Beispiel:

    public class ShapeData
    {
      public int X { get; set; }
      public int Y { get; set; }
      public int Width { get; set; }
      public int Height { get; set; }
    }
    
    public interface IShapeView
    {
      void Display(ShapeData data);
    }
    
    public class Shape
    {
      public ShapeData Data { get; set; }
      public IShapeView View { get; set; }
    
      public void Display()
      {
        if(this.Data != null && this.View != null)
        {
          this.View.Display(this.Data);
        }
      }
    }
    

    Perfekt, sollte alles klar sein oder? Nun wollen wir eine Ellipse darstellen?

    public class EllipseView
      : IShapeView
    {
      public void Display(ShapeData data)
      {
        // Das Ding zeichnen oder auf der Konsole ausgeben oder was auch immer.
      }
    }
    
    // ...
    
    Shape shape = new Shape();
    shape.Data = new ShapeData();
    // Werte zuweisen ...
    shape.View = new EllipseView();
    
    shape.Display();
    

    Gut ... jetzt hätte ich aber gerne dieses Rechteck auch als Begrenzung um die Ellipse angezeigt. Kein Problem!

    public class RectView
      : IShapeView
    {
      public void Display(ShapeData data)
      {
        // Einfach DrawRect(data.X, data.Y, data.Width, data.Height) oder sowas ...
      }
    }
    
    // ...
    // Wir können die Variable shape von vorhin gleich wiederverwenden.
    // Die Daten werden belassen, wir verändern nur die View.
    shape.View = new RectView();
    shape.Display();
    

    Was will man mehr? 🙂
    Das kann man nun um beliebige Views erweitern, welche in das einfache Schema mit dem Rechteck passt. Man kann sogar theoretisch Kreis-Views machen, obwohl dies gar nicht nötig ist, da man dies von den Daten her erzwingen könnte mit einer EllipseView. Da wäre zum Beispiel eine BigCircleView und eine SmallCircleView möglich, welche jeweils entweder den grössten oder kleinsten Wert für den Radius von der Länge und Breite heranziehen. Gleiches kann man dann auch für das Quadrat machen, obwohl man es bereits mit RectView und korrekten Daten erreichen kann. Für die korrekten ShapeDaten könnte man sogar entsprechende statische Funktionen anbieten:

    public static ShapeData CreateCircle(int centerX, int centerY, int radius)
    {
      // ...
    }
    
    public static ShapeData CreateSquare(int x, int y, int length)
    {
      // ...
    }
    

    Das ist meiner Meinung nach sehr schönes MVC. So sollte die Objektorientierung erklärt werden und nicht irgendwie probieren einen Kreis von einer Ellipse abzuleiten oder umgekehrt und solchen Unsinn 🙂

    Problematisch wird es eben erst, wenn die Daten auch ein polymorphes Objekt darstellen und man nicht an alle Daten herankommt, an welche man herankommen möchte. Dann wird es grundsätzlich knifflig, aber nicht unmöglich. Man kann zum Beispiel für jeden Filter-Typ eine View im Controller registrieren. Der Controller sucht dann für den Datentyp gleich das richtige View aus. Im View muss dann eben ein Up-Cast durchgeführt werden.

    Ich habe jetzt nicht die vollständige .Net Bibliothek im Kopf und bin zu faul nachzuschauen, aber so ganz grob, würde dies wohl so aussehen:

    public class FilterDisplayController
    {
      private SortedDictionary<Guid, IFilterView> m_views;
    
      public void RegisterView<T>(IFilterView view)
        where T : IFilter
      {
        Guid guid = typeof(T).GUID;
        m_views[guid] = view;
      }
    
      public void Display(IFilter filter)
      {
        Guid guid = filter.GetType().GUID;
    
        IFilterView view;
        if(m_view.TryGetValue(guid, out view))
        {
          view.Display(filter);
        }
      }
    }
    

    Vielleicht könnte man die View-Zuordnung auch statisch setzen ...

    Naja, aber sollte auch nur ein Erläuterungsbeispiel sein, muss ja jetzt nicht gleich perfekt sein. Zudem ist es nun 2 Uhr und ich wollte um 23:30 Uhr ins Nest, damit ich morgen/heute mich noch weiter in Lua einarbeiten kann.

    Herr Dravere, lernen sie endlich rechtzeitig in ihr Nest zu verschwinden! 🙄 😃

    Grüssli



  • Dravere schrieb:

    mogel schrieb:

    ich betrachte Interfaces als Bestandteil von C ... wärend Klassen zu M gehören ... wir haben hier also schon zwei Ansichten

    Siehe Antwort von asc. Ich würde dir empfehlen, dich mit dieser Thematik nochmals auseinander zu setzen.

    was genau zum M / zum V / zum C gehört ist reine Interpretationssache ... beim MVC geht es darum die Funktionalität von der Ansicht zu trennen

    Sofern sich dein Filter an die definierten Konventionen hält, sicher.

    irgendwie hängst Du damit das Model fest an den View

    Aber wer würde dir verbieten, ein eigenes View für deinen Filter zu schreiben, welches von IFilterView ableitet?

    das kann von was auch immer ableiten - z.B. Control

    Ich persönlich erkläre es noch gerne an diesem Beispiel:
    [...Kapselung von View & Model in einer Klasse..]

    Im View muss dann eben ein Up-Cast durchgeführt werden.

    Vielleicht könnte man die View-Zuordnung auch statisch setzen ...

    ah - und was habe ich gemacht ... ich habe das View statisch an das Model gehangen

    der Fehler ist evt. das ich da direkt gleich ein Control gemacht habe und somit die Möglichkeiten festgelegt habe ... da sollte wohl wirklich eher ein IFilterView hin ... allerdings würde ich dennoch beibehalten das der Filter seinen View selber liefert ... wenn da noch eine entsprechende Methode hinkommt um den IFilterView entsprechend bei der Erzeugung des Filters zu setzen, ist dem Filter sein View völlig egal ... außerdem sparst Du Dir das wilde Casten und/oder Suchen nach dem richtigen View zum Model

    hand, mogel


  • Administrator

    mogel schrieb:

    Dravere schrieb:

    mogel schrieb:

    ich betrachte Interfaces als Bestandteil von C ... wärend Klassen zu M gehören ... wir haben hier also schon zwei Ansichten

    Siehe Antwort von asc. Ich würde dir empfehlen, dich mit dieser Thematik nochmals auseinander zu setzen.

    was genau zum M / zum V / zum C gehört ist reine Interpretationssache ... beim MVC geht es darum die Funktionalität von der Ansicht zu trennen

    Lies doch bitte mal die Stelle genau, welche dort steht. Danach schlägst du bitte die Begriffe Architektur- und Entwurfsmuster nach. Ob man es nun als Architektur- oder Entwurfsmuster betrachtet, macht keinen unterschied darin, was zu M, was zu V und was zum C gehört, das ist bei beiden gleich.

    Es geht eigentlich eher darum, auf welcher Ebene man MVC anwendet. Wenn man es als Architekturmuster sieht, dann wendet man MVC an, um die Softwareachritektur aufzubauen. Also quasi in einem übergeordneten Grundgedanke. Das kann man durch die Verwendung von Schichten (Layers) erreichen. Ist vor allem im Bereich von Enterprise-Software gang und gäbe.
    Wenn man es als Entwurfsmuster sieht, dann verwendet man es direkt im Code, um einzelne Bereiche umzusetzen. Wie es hier gerade besprochen wurde.

    mogel schrieb:

    Sofern sich dein Filter an die definierten Konventionen hält, sicher.

    irgendwie hängst Du damit das Model fest an den View

    Klar hat man eine gewisse Bindung, dass hat ja noch nie jemand abgestreitet. Die Frage ist nur und ich glaube, dass ich mich mindestens zum dritten Mal wiederhole, wie stark man diese Bindung macht. Meine Bindung ist extrem lose und funktioniert durch Funktionsparameter. Man kann alles jederzeit austauschen. Man kann auch andere Views an das Model fest anbinden. Schliesslich ist MVC keine 1:1:1 Beziehung, sondern eine m✌c Beziehung.

    mogel schrieb:

    Aber wer würde dir verbieten, ein eigenes View für deinen Filter zu schreiben, welches von IFilterView ableitet?

    das kann von was auch immer ableiten - z.B. Control

    Klar kann man es von was auch immer ableiten. Darum ging es hier ja nicht. In diesem Fall war einfach die Basis für alle View IFilterView, sofern es über diesen Controller geht. Du kannst aber einen neuen Controller schreiben, welcher mit IFilter umgehen kann und auch andere Arten von Views verwaltet. Das ist ja der Trick von MVC. Man ist äusserst flexibel und kann überall alle Komponenten beliebig austauschen. Das geht bei dir nicht, weil du das View zum fixen Bestandteil der Daten gemacht hast, bzw. direkt zum Bestandteil der Schnittstelle der Daten!

    mogel schrieb:

    Ich persönlich erkläre es noch gerne an diesem Beispiel:
    [...Kapselung von View & Model in einer Klasse..]

    Im View muss dann eben ein Up-Cast durchgeführt werden.

    Vielleicht könnte man die View-Zuordnung auch statisch setzen ...

    ah - und was habe ich gemacht ... ich habe das View statisch an das Model gehangen

    Ich meinte, dass man die Variable m_views als statische Variable nehmen könnte. Dann ist die View nicht statisch an das Model fixiert. Man hat immer noch die freie Möglichkeit das ganze anders zuzuordnen.

    mogel schrieb:

    der Fehler ist evt. das ich da direkt gleich ein Control gemacht habe und somit die Möglichkeiten festgelegt habe ... da sollte wohl wirklich eher ein IFilterView hin ... allerdings würde ich dennoch beibehalten das der Filter seinen View selber liefert ... wenn da noch eine entsprechende Methode hinkommt um den IFilterView entsprechend bei der Erzeugung des Filters zu setzen, ist dem Filter sein View völlig egal ... außerdem sparst Du Dir das wilde Casten und/oder Suchen nach dem richtigen View zum Model

    Damit sagst du aus, dass das Model dem Controller das View liefern soll. Lies in jeder beliebigen Quelle zu MVC nach, du wirst überall lesen können, dass du mit dieser Aussage auf dem absoluten Holzweg bist. Denn damit machst du das View zum Bestandteil der Schnittstelle des Model. Aber genau das will man schliesslich verhindern. Man will die Schnittstellen unabhängig gestalten, damit man jede Komponente nach belieben austauschen kann.

    Grüssli



  • mogel schrieb:

    was genau zum M / zum V / zum C gehört ist reine Interpretationssache...

    Dann lies dir bitte auch den MVC-Artikel durch.

    mogel schrieb:

    ...beim MVC geht es darum die Funktionalität von der Ansicht zu trennen

    Zumal du genau gegen deine eigene Aussage handelst. Bei dir ist die Ansicht eben nicht von der Funktionalität getrennt, da ein konkretes Wissen von den Controls (einer Ansicht, eine Einschränkung die auch der Trennung widerspricht) vorhanden ist.

    Nachtrag: Und was den Verweis auf die Entwurfsmuster angeht: Deine MVC-Interpretation wäre in etwa so, als würde ich das Strategiemuster so interpretieren, das ich drei fixe Funktionen über einen switch ansteuere, ohne Flexibilität.



  • ...wobei noch anzumerken wäre dass die von Dravere beschriebene Technik eine allgemeine ist und erst einmal nichts mit MVC zu tun hat. Dass MVC sich diese Technik zu Nutze macht ist ein anderes Thema.


  • Administrator

    witte schrieb:

    ...wobei noch anzumerken wäre dass die von Dravere beschriebene Technik eine allgemeine ist und erst einmal nichts mit MVC zu tun hat. Dass MVC sich diese Technik zu Nutze macht ist ein anderes Thema.

    Ist das nicht ein bisschen Erbsenzählerei? 🙂
    Weil MVC nur eine Beschreibung eines Konzepts ist, muss man schlussendlich irgendeine Technik einsetzen, um dieses Konzept umzusetzen.

    Grüssli



  • Uns was läuft da mit meiner Aussage nicht konform?


  • Administrator

    witte schrieb:

    Uns was läuft da mit meiner Aussage nicht konform?

    Nichts, ich sage ja nur, dass es ein bisschen Erbsenzählerei ist. Denn ohne Technik kannst du auch kein MVC umsetzen. Daher halte ich die Bemerkung, dass die Technik nichts mit MVC zu tun hat, ein wenig für überflüssig. Deine Aussage läuft nämlich in etwa darauf hinaus:
    Eine Technik hat nichts mit einem Konzept zu tun. Um das Konzept umzusetzen, verwendet man allerdings eine Technik.

    Kann man davon nicht einfach implizit ausgehen? Muss man das wirklich noch explizit erwähnen? Ist das so wichtig?
    Das soll kein Vorwurf sein. Vielleicht hattest du einfach nur einen wichtigen Hintergrundgedanken dabei, welcher mir gerade entgeht. Deshalb frage ich nach 😉

    Grüssli



  • @Dravere
    Wir haben uns wahrscheinlich schon wieder falsch verstanden. Ich habe mich simpel auf das "abstrakte" Shape bezogen welches seine Daten und Präsentation von einem übergeordneten Controller injiziert bekommt:

    Dravere schrieb:

    Shape shape = new Shape();
    shape.Data = new ShapeData();
    // Werte zuweisen ...
    shape.View = new EllipseView();
    

    Diese Technik ist nach meinem Verständnis ein dependency injection/inversion of control wie es von Fowler and friens populär gemacht wurde. Also das Objekt bestimmt nicht selber mit wem es etwas zu tun haben möchte sondern bekommt seine mates reingewürgt. Dass diese Technik für MVC notwendig/sinnvoll ist will ich nicht bestreiten.
    Meine Anmerkung mag vllt wie Erbsenzählerei/Trivialität anmuten aber ich habe gerade ein Projekt auf den Tisch wo es genau darum geht. Mein ehemaliger Kollege hat mir als Projekt ein Reporting system vermacht wo alles mögliche erbt/vererbt, verklebt und verbacken ist und Objekte an die Persistenzschicht gefesselt sind obwohl sie gar keine Persistenz besitzen. Als ich diesen Thread gelesen habe habe ich gedacht "genauso hätte es mein Kollege machen müssen".
    Jetzt habe ich erstmal das alles aufgerissen und genau dieses von Dir beschriebene Prinzip angewandt: Die Berichte bekommen ihren Plotter (Pie, Bar, ...), ihre Daten als verschiedene Repository-Objekte und die Gruppierungen über entsprechende Modelobjekte von außen zugewiesen und arbeiten mit ihnen über Schnittstellen. Jetzt kann sich jeder seinen Bericht wie in einem Restaurant mit einer Speisekarte zusammenstellen, alle sind glücklich und ich kann mich endlich wieder meinen Aufgabe widmen.


Anmelden zum Antworten