• +49 431 239710
  • info@fastleansmart.com
    MENUMENU
    • SOLUTIONS
          • PRODUKTE



          • FLS VISITOUR
          • FLS PORTAL
          • FLS MOBILE
          • DISPATCH NOW
          • TECHNOLOGIEN



          • PowerOpt
          • Künstliche Intelligenz
          • BPMN
          • Integration
          • ANWENDUNGEN



          • Field Service Management
          • Mobile Workforce
          • Terminplanung
          • Tourenplanung
          • Mobile Lösungen
          • Wartung und Instandhaltung
          • Auslieferung
    • ÜBER FLS
          • ÜBER FLS



          • Unternehmen
          • Jobs
          • Standorte
          • Blog
          • Warum FLS?
          • FAQ
          • KUNDEN



          • Kunden
          • Branchen
          • Case Studies
          • Kundenstimmen
          • PARTNER



          • Überblick Partner-Programm
          • Business Process Consulting
          • Managed Service Provider
          • System Integrator
          • Value Added Reseller
          • OEM
          • PARTNER PORTAL



          • Registrierung
          • Log-In
    • KARRIERE
    • KONTAKT

          • SIE ERREICHEN UNS




            Telefon: +49 431 239710


            E-Mail: info@fastleansmart.com


          • NEWSLETTER




            Gratis FLS ECHTZEIT-NEWS in Ihr Postfach

            Stets optimal informiert. News abonnieren  ›


          • UNVERBINDLICH TESTEN




            FLS-DE-Demo-Buchen-banner
    • DE
    • EN
    • NL
    DEMO BUCHEN
    ✕

    BLOG / RESEARCH – DESERIALISIERUNG


    DESERIALISIERUNG UND DAS DEKORATOR-MUSTER


    KONTAKT ›

    E ine in Software-Projekten häufig auftretende Aufgabe ist die Serialisierung und anschließende Deserialisierung von Daten. Dabei handelt es sich um die Darstellung komplexer Daten in einer Zeichenkette (Serialisierung), die dann z.B. auf einem Datenträger gespeichert oder über Netzwerke übertragen werden kann, wobei der Empfänger die empfangene Darstellung wieder in eine für ihn geeignete Form umwandelt (Deserialisierung).

    Ein typisches Beispiel ist die Serialisierung von Objektgraphen in XML-Dokumente. Das .NET-Framework bietet dafür z.B. durch XmlSerializer gute Unterstützung. Diese allein reicht aber nicht aus, wenn dabei Objektreferenzen nicht nur top-down, sondern auch bottom-up verwaltet werden sollen. Wir stellen eine an die vorhandenen Strukturen angepasste Lösung vor, die im Kontext eines etablierten Software-Entwurfsmusters1 beleuchtet wird.


    EINFÜHRUNG


    Zuerst gehen wir auf ein bei der Serialisierung auftretendes Problem ein und beschreiben den technischen Hintergrund eines Lösungsansatzes. Dann erläutern wir eine Umsetzung mit Hilfe des Dekorator-Musters. Weiter diskutieren wir Vor- und Nachteile unserer Implementierung2 und schließen mit einem kurzen Ausblick.


    1. OBJEKTREFERENZEN UND OBJEKTIDENTITÄT


    Wenn in der Software-Entwicklung etwas komplexere, dynamische Datenstrukturen nötig sind, hat man schnell einen Baum implementiert. Ein Knotentyp für diesen sieht dann etwa wie folgt aus, wobei Id das einzige Nutzdatum sein soll.

    Implementierung:
    public class Node 
    {
        public string Id;
        public List<Node> Children = new List<Node>();
    }
    

    Dieser Typ kann ohne Angabe von Attributen durch XmlSerializer serialisiert und deserialisiert3 werden. Eine direkte Navigation ist aber immer nur top-down möglich, nämlich vom Elternobjekt zu seinen Kindern, aber nicht umgekehrt. Dies kann von einem betroffenen Entwickler schnell als Mangel empfunden werden. Es wird dann reflexhaft ein neues Feld, etwa public Node Parent hinzugefügt, das dann immer konsistent gesetzt werden muss. Beim Serialisieren fällt auf, dass XmlSerializer eher schlecht mit mehrfach referenzierten Objekten umgehen kann – bei korrekter Belegung von Parent enthält der Objektgraph einen Kreis, der zu dem vergeblichen Versuch führt, die gleichen Objekte unendlich oft zu serialisieren. Der Grund dafür ist, dass die Objektidentitäten nicht berücksichtigt werden.

    Abhilfe schafft das Attribut XmlIgnore, mit dem Parent von der Serialisierung und Deserialisierung ausgeschlossen wird4. Nachdem die Serialisierung damit wieder möglich ist, kommt beim Entwickler erneut milde Frustration auf – soll jetzt etwa in einem der Deserialisierung nachgelagerten Schritt (z.B. durch Tiefensuche) jeweils das Feld Parent individuell gesetzt werden? Das erscheint überflüssig, da die nötige Information ja während der Deserialisierung vorhanden ist.

    Der Schlüssel ist ein detaillierteres Verständnis der Serialisierung und Deserialisierung. Das Befüllen von Containern5 kann dabei nämlich über ICollection erfolgen, was auch erklärt, warum XmlSerializer mit vielen verschiedenen Containern6 umgehen kann. Eine Möglichkeit ist also das Entwickeln einer Implementierung7 von ICollection, die an den in ihr enthaltenen Objekten das Feld Parent über eine (ausschließlich dafür geschaffene) weitere Schnittstelle pflegt. Dies löst nicht nur das Problem der Serialisierung und Deserialisierung, sondern verlagert auch das Setzen von Parent vom umgebenden Code8 in den Container.

    Die generisch implementierte Schnittstelle für den Zugriff auf Parent besteht dabei etwas unspektakulär aus nur einer einzigen Eigenschaft mit zwei Akzessoren.

    Implementierung:
    public interface IChild<T>
    {
        T Parent { get; set; }
    }
    

    Nachdem wir also den technischen Rahmen geklärt haben, werden wir die gewünschten Schritte mit Hilfe des Dekorator-Musters implementieren, wobei wir noch eine verbesserte Trennung der Zuständigkeiten erhalten. Dabei werden wir durch Einschränkung des Typparameters9 T sicherstellen, dass der verwendete Typ für die Elemente des Containers die Schnittstelle IChild implementiert.


    2. UMSETZUNG MIT HILFE DES DEKORATOR-MUSTERS


    Das Dekorator-Muster basiert zunächst auf einer Schnittstelle für die zu dekorierenden Objekte, die in unserem Fall die bereits bestehende Schnittstelle ICollection ist, auf der auch XmlSerializer arbeitet. Dann wird eine abstrakte Dekorator-Basisklasse10 erstellt, die eine Referenz auf das zu dekorierende Objekt vom Typ ICollection speichert und selbst ICollection implementiert. Alle Felder der Schnittstelle werden an das referenzierte Objekt durchgeschleift und sind, wo es möglich ist, als virtual deklariert. Somit müssen in konkreten von CollectionDecorator erbenden Klassen nur diejenigen Felder implementiert werden, deren Verhalten sich ändert.

    Implementierung:
    public abstract class CollectionDecorator<T> : ICollection<T>
    {
        private ICollection<T> Collection;
        public CollectionDecorator (ICollection<T> Collection)
        {
            this.Collection = Collection;
        }
        // implementation of ICollection<T> is omitted
    }
    

    Dabei ist zu beachten, dass die Referenz auf das zu dekorierende Objekt selbst als private deklariert ist, also nach seinem Setzen im Konstruktor von außen nicht mehr zugänglich ist. Eine minimale, aber vollständig parametrisierte Implementierung des gewünschten konkreten Dekorators sieht dann folgendermaßen aus.

    Implementierung:
    public class ParentDecorator<T> : CollectionDecorator<T> where T : IChild<T>
    {
        private T Parent;
        public ParentDecorator(ICollection<T> Collection, T Parent)
            : base(Collection)
        { this.Parent = Parent; }
        public override void Add(T item)
        {
            base.Add(item);
            if (null != item) item.Parent = Parent;
        }
        public override bool Remove(T item)
        {
            var Result = base.Remove(item);
            if (Result && null != item) item.Parent = default(T);
            return Result;
        }
    }
    

    Die so vorbereiteten Strukturen ermöglichen eine äußerst kurze Implementierung von Node, da die gesamte „Intelligenz“ im Dekorator steckt und sowohl für XmlSerializer als auch den Anwendungscode transparent ist.

    Implementierung:
    public class Node : IChild<Node>
    {
        public string Id;
        [XmlIgnore]
        public Node Parent { get; set; }
        public readonly CollectionDecorator<Node> Children;
        public Node()
        {
            this.Children = new ParentDecorator<Node>(new List<Node>(), this);
        }
    }
    


    3. VOR- UND NACHTEILE DER LÖSUNG


    Wie es bei der Ausarbeitung von Details in einem vorgegebenen technischen Kontext immer der Fall ist, haben die bei der Implementierung getroffenen Entscheidungen natürlich Konsequenzen. Um ein realistisches Bild zu zeichnen, stellen wir also klar die Vor- und Nachteile gegenüber.

    Zunächst kann Parent von außen gesetzt werden, obwohl dies ausschließlich von ParentDecorator aus erwünscht ist. Ebenso nachteilig ist die sehr starke Anpassung an XmlSerializer, was eine direkte Übertragung des Ansatzes auf DataContractSerializer unmöglich macht11. Auffallend ist die Verwendung von CollectionDecorator in Node. Intuitiv würde man erwarten, dass ICollection ausreicht. Das ist aber überraschenderweise nicht so, da XmlSerializer zwar abstrakte Klassen, aber keine Schnittstellen serialisieren kann – selbst dann nicht, wenn ICollection bei der Deserialisierung von dem sie aggregierenden Typen instanziiert wird12. Weiter könnte ein externes Setzen von Collection fatale Folgen haben, falls ein Container verwendet werden würde, dessen Parent zu einem anderen Objektgraphen gehört oder der gar nicht mit ParentDecorator ausgestattet ist.

    Durch den Zugriffsmodifikator readonly für Children können wir dies jedoch verhindern und somit erreichen, was uns bei Parent nicht gelungen ist. Der Zugriff auf den im Konstruktor von Node erzeugten Container vom Typ List ist durch Zugriffsmodifizierer eingeschränkt und Node selbst speichert keine Referenz auf ihn. Dadurch wird die Tendenz des Dekorator-Musters, die Objektidentitäten zu verschleiern, stark abgemildert. Da schließlich der Zugriff der Dekoratoren nur über ICollection erfolgt, können mindestens alle im .NET-Framework implementierten generischen Container verwendet werden, die diese Schnittstelle implementieren.


    AUSBLICK


    Wir haben eine Verwaltung von Objektreferenzen über das Dekorator-Muster so implementiert, dass sie für die Serialisierung komplett und den Anwendungscode zumindest weitestgehend transparent ist. Dadurch fügt sich unsere Implementierung nahtlos in ihre Umgebung ein, ist durch die Trennung von Zuständigkeiten wiederverwendbar und kann auch ohne vollständige Kenntnis der Details in bestehende Implementierungen integriert werden. Da in unserem Objektgraphen nur ein einziger Typ vorkommt, hat ParentDecorator auch nur einen einzigen Typparameter. Wenn im Objektgraphen mehr als ein Typ vorkommt, was etwa im Zusammenwirken mit dem Kompositum-Muster der Fall sein kann, wird es etwas komplexer. Gleichzeitig wird es aber auch spannender, weil wir uns dann über die Gemeinsamkeiten der vorkommenden Typen bewusst werden müssen, um eine Serialisierung und Deserialisierung über einen einheitlichen Mechanismus vorzunehmen.


    1 Karl Eilebrecht, Gernot Starke: Patterns kompakt – Entwurfsmuster für effektive Software-Entwicklung, Spektrum akademischer Verlag, 2010.

    2 Die Implementierung ist zusätzlich als Projektmappe für Visual Studio verfügbar unter

    https://github.com/DbRRaU6m/Serialization

    3 https://msdn.microsoft.com/de-de/library/58a18dwa(v=vs.120).aspx


    4 https://msdn.microsoft.com/


    5 Bei bloßer Anwendung ist der genaue Ablauf der Serialisierung einem Entwickler typischer- und berechtigterweise nicht voll bewusst; stattdessen wird der gesamte Ablauf als „automagisch“ hingenommen.


    6 https://msdn.microsoft.com/de-de/library/system.collections.generic(v=vs.110).aspx


    7 http://www.thomaslevesque.com/2009/06/12/c-parentchild-relationship-and-xml-serialization/


    8 Das Setzen bzw. Löschen von Parent dient der Aufrechterhaltung einer Invariante des Objektgraphen. Möglicherweise unterstützt es die Kapselung stärker, diese Aufgabe in den Klassen zu implementieren, die am Objektgraphen beteiligt sind, und nicht außerhalb davon.

    9 www.fastleansmart.com/blog/die-drei-interessantesten-features-von-cs/


    10 Sie kann auch als Basisklasse weiterer Dekoratoren dienen, die sich dann miteinander verketten lassen. Dadurch ist es möglich, Objekte mit verschiedenem Verhalten zu erzeugen (und in einem gewissen Rahmen das Verhalten sogar zur Laufzeit zu verändern), ohne neue Typen zu implementieren.


    11 Dies ist ein geringer Nachteil, da DataContractSerializer mit Kreisen im Objektgraph umgehen kann:

    https://msdn.microsoft.com/en-us/library/hh241056(v=vs.100).aspx


    12 Die Klasse ParentDecorator besitzt keinen parameterlosen Konstruktor, was eine direkte Erzeugung durch XmlSerializer unmöglich macht. Stattessen erfolgt die Erzeugung im Konstruktor von Node, was aus Gründen der Sichtbarkeit der benötigten Argumente auch die einzige sinnvolle Stelle ist.


    AUTOR    



    DR. FLORIAN DIEDRICH
    Software-Entwickler
    Berichtet über die Themen Software, Technologien und Entwicklung

    +49 (0)431 23971-0
    E-Mail schicken  ›

    FLS ECHTZEIT-NEWS
    Jederzeit gut informiert:
    Der FLS-Newsletter.

    Mit aktuellen Themen rund um
    FLS-Produkte und -Services direkt per E-Mail in Ihr Postfach

    ZUR INFO & ANMELDUNG ›

    ARTIKEL TEILEN    




    ‹  Zurück zur Übersicht



    NOCH EINEN MOMENT ZEIT?


    • 2. November 2022

      ERSTES ENTWICKLER-BARCAMP BEI FLS


      Mehr lesen
    • FLS E-Book "Field Service Management 2030: Megatrends"
      14. Juli 2022

      E-BOOK: FIELD SERVICE MANAGEMENT 2030 – MEGATRENDS IM AUSSENDIENST


      Mehr lesen
    • Engineer Diary Management
      30. Januar 2023

      WIE EINE ERSTKLASSIGE TOURENPLANUNG DEN AUSSENDIENST NACHHALTIGER MACHT


      Mehr lesen





     ZU DEN BLOG-KATEGORIEN


    CUSTOMERS



    RESEARCH



    COMPANY



    EVENTS



    SOLUTIONS



    MEDIA



      Start  ›  DESERIALISIERUNG UND DAS DEKORATOR-MUSTER



    PRODUKTE

    FLS VISITOUR

    FLS PORTAL

    FLS MOBILE

    DISPATCH NOW


    WARUM FLS?

    TECHNOLOGIEN

    PowerOpt

    Künstliche Intelligenz

    BPMN

    Integration


    PowerOpt – live?

    JETZT TESTEN  ›

    ANWENDUNGEN

    Field Service Management

    Mobile Workforce

    Terminplanung

    Tourenplanung

    Mobile Lösungen

    Wartung & Instandhaltung

    Auslieferung

    KUNDEN

    Kundenstimmen

    Case Studies

    Branchen


    SERVICES

    Consulting

    Projekt

    Customer Services

    UNTERNEHMEN

    Karriere

    Standorte

    FAQ

    Code of Conduct


    NEWS

    Blog

    Webinare

    Events

    Newsletter

    PARTNER

    Partner-Programm

    BPC

    Managed Service Provider

    System Integrator

    Value Added Reseller

    OEM


    Registrierung

    Partner-Portal Log-In


    Folgen Sie uns

       FLS-social-media-icon-linkedIn    FLS-social-media-icon-xing    FLS-social-media-icon-youtube



    Sicherheit und Qualität nach höchsten Standards. Unsere Stand­orte in Deutsch­land, den Nieder­landen und Groß­britannien sind im Bereich Infor­mations­sicher­heits-Manage­ment (ISO 27001) ISO-zertifi­ziert. Zudem können die deutschen Standorte und die in Groß­britannien ISO-Zertifi­zierungen in den Bereichen Qualitäts­management (ISO 9001) und Umwelt­management (ISO 14001) vorweisen. Mehr Infos ›

    © FLS – FAST LEAN SMART   ·   Datenschutzerklärung   ·   AGB  ·   Impressum
      DEMO BUCHEN
      DE
      • DE
      • EN
      • NL
      • +49 431 239710
      • info@fastleansmart.com