Laden...

[Review | Frage] Vorgehen bei komplexer Datenverarbeitung

Erstellt von Killerkrümel vor 5 Jahren Letzter Beitrag vor 5 Jahren 3.284 Views
K
Killerkrümel Themenstarter:in
166 Beiträge seit 2008
vor 5 Jahren
[Review | Frage] Vorgehen bei komplexer Datenverarbeitung

Hallo Community,

es gibt einen zu nutzenden RestService, welcher mir eine Objecthierarchie mit bis zu 100 Objekten ala


List<Container>=> 
Container => 
    List<ContainerItem> => 
    ContainerItem => 
        List<Item> => 
        Item

wiedergibt, von denen Ich u.U. sogar die einzelne Items, auch bestimmte Items brauche.
Daher überlege ich mir gerade, wie ich die Datenaufarbeitung am besten realisieren könnte.
Folgende Überlegung:

public class CLAPFactory : IFactory
    {
        public readonly Container<IAnalyticalActivityP> _activityContainer;
        private readonly Container<IAnalyticalElementaryTaskRecord> _aetrContainer;

        public CLAPFactory()
        {
            _activityContainer = new Container<IPersistableData>();
            _aetrContainer = new Container<IPersistableData>();
        }

        public void Persist<TPersistableData>(IList<TPersistableData> collection) where TPersistableData : IPersistableData
        {
            foreach (var data in collection)
            {
                _activityContainer.Add(data.Key, (IAnalyticalActivityP)data);
            }
        }

        public void Persist<TPersistableData>(TPersistableData data) where TPersistableData : IPersistableData
        {
            _activityContainer.Add(data.Key, (IAnalyticalActivityP)data);
        }

        public TPersistableData LoadableData<TPersistableData>(string key) where TPersistableData : IPersistableData
        {
            if (typeof(TPersistableData) == typeof(IAnalyticalActivityP))
                return (TPersistableData)_activityContainer[key];

            if (typeof(TPersistableData) == typeof(IAnalyticalElementaryTaskRecord))
                return (TPersistableData)_activityContainer[key];

            return default(TPersistableData)
        }
    }

    public interface IFactory
    {
        void Persist<TPersistableData>(IList<TPersistableData> collection) where TPersistableData : IPersistableData;

        void Persist<TPersistableData>(TPersistableData data) where TPersistableData : IPersistableData;

        TPersistableData LoadableData<TPersistableData>(string key) where TPersistableData : IPersistableData;
    }
public class Container<TPersistableData> : Dictionary<string, TPersistableData> where TPersistableData : IPersistableData
    {
        public Container()
        {
        }

        public Container(int capacity) : base(capacity)
        {
        }

        public Container(IEqualityComparer<string> comparer) : base(comparer)
        {
        }

        public Container(int capacity, IEqualityComparer<string> comparer) : base(capacity, comparer)
        {
        }

        public Container(IDictionary<string, TPersistableData> dictionary) : base(dictionary)
        {
        }

        public Container(IDictionary<string, TPersistableData> dictionary, IEqualityComparer<string> comparer) : base(dictionary, comparer)
        {
        }

        protected Container(SerializationInfo info, StreamingContext context) : base(info, context)
        {
        }
    }

Wie kann ich verhindern, für jedes TPersistableData-INterface eine eigene Interfaceabfrage zu machen?
(vgl. If(typeof)[...])

Ist dies überhaupt der richtige Ansatz?

W
955 Beiträge seit 2010
vor 5 Jahren

Schau dir mal das Entwurfsmuster Visitor an.

16.806 Beiträge seit 2008
vor 5 Jahren

es gibt einen zu nutzenden RestService, welcher mir eine Objecthierarchie mit bis zu 100

Ist dies überhaupt der richtige Ansatz?

Prinzipiell ist es eine Bad Practise große, komplexe Objekte mit REST anzunehmen, oder zurück zu geben.
Daher sind Navigation Properties auch nicht Teil der Rückgaben von OData oder anderen Hypermedia-Protokollen wie GraphQL oder Siren.
Das wiederum lässt den Schluss zu, dass Du überhaupt keinen REST sondern einfach einen simplen Json-Service schreibst; denn das schlanke Navigieren über Objekte durch Url-Segmente fällt bei Dir ja flach.

Ich hab sehr viel mit APIs und API Design zutun und noch keinen Grund gefunden, wirklich solche großen Objekte über eine API zurück geben zu müssen.
Was genau ist der Grund, dass es hier der Fall ist?

K
Killerkrümel Themenstarter:in
166 Beiträge seit 2008
vor 5 Jahren

Das wiederum lässt den Schluss zu, dass Du überhaupt keinen REST sondern einfach einen simplen Json-Service schreibst; denn das schlanke Navigieren über Objekte durch Url-Segmente fällt bei Dir ja flach.
[...]
Was genau ist der Grund, dass es hier der Fall ist?

Hallo Abt,

Ich muss einen Service aufrufen, welcher basierend auf einer ID eine Struktur als JSON zurückgibt, die oben definiert ist (Exemplarisch):

Eine Liste aus Containern
Jeder **Container **hat eine Liste aus SubContainern.
Jeder **SubContainer **hat eine Liste aus SubContainerEigenschaften
Jede **ContainerEigenschaft **kann, muss aber nicht, eine Liste aus **SubEigenschaften **enthalten

Es können 1-n Container vorkommen
Es können 1-n SubContainer vorkommen
Es können 1-n SubContainerEigenschaften vorkommen
Es können 0-n SubEigenschaten vorkommen.

Stell es dir am besten wie eine Fertigungsprozesskette vor:

Auto ist der Container.
    Türenmontieren ist ein SubContainer
        Fenster-vorne ist eine SubContainerEigenschaft
            Fensterfarbe ist eine SubEigenschaft
            [...]   

        Fenster-hinten ist eine SubContainerEigenschaft
        [...]

    Karosserie montieren ist ein SubContainer
    [usw...]

ich brauche in der Anwendung nun zugriff auf die FensterFarbe, von
denen es wie gesagt 0-4 geben kann.

P.S.:
Ich kann die Antwort des Services nicht ändern/anpassen, ich muss den kommenden json string nutzen.

K
Killerkrümel Themenstarter:in
166 Beiträge seit 2008
vor 5 Jahren

@ Witte - die Idee mit dem VisitorPattern ist interessant.
Jedoch habe ich es entweder Missverstanden, oder es ist für meinen Ansatz nicht hilfreich. Der Kerngedanke des Patterns ist es ja, den Verarbeitungsalgorithmus von Objekten zu trennen (IMO)
Jedoch will ich nichts verarbeiten, sondern möglichst zuverlässig und schnell an einzelne Eigenschaften der SubObjekte herankommen.

16.806 Beiträge seit 2008
vor 5 Jahren

Ich versteh es vermutlich immer noch nicht... (und evtl. bin ich nicht der Einzige..)

Worum geht es Dir denn? Was meinst Du mit "schnell und zuverlässig an Eigenschaften" kommen?
Geht es Dir um die Serialiserung der Json-Antwort, oder willst Du den Wert haben?

Reden wir hier von einer rekursiven Herarchie und ein Container ist das gleiche wie ein SubContainer, oder sind das zwei verschiedene Objekte(/Klassen) ?

K
Killerkrümel Themenstarter:in
166 Beiträge seit 2008
vor 5 Jahren

Hallo Abt,

vielen Dank vorab für deine Mühen.

Worum geht es Dir denn?

  • Zugriff auf die Unterschiedlichen Elemente der Kette

Was meinst Du mit "schnell und zuverlässig an Eigenschaften" kommen?
Geht es Dir um die Serialisierung der Json-Antwort, oder willst Du den Wert haben?

  • Eventuell ist dies das gleiche. Ich möchte auf Werte innerhalb der Kette zugreifen

Reden wir hier von einer rekursiven Hierarchie und ein Container ist das gleiche wie ein SubContainer, oder sind das zwei verschiedene Objekte/Klassen) ?

  • Nein, Der Container ist ein eigenes Objekt, der SubContainer auch, also verschiedene Klassen.

Mir geht es darum, mit möglichst wenig Aufwand auf Elemente und ihre Werte innerhalb der "Produktionskette" zugreifen zu können.

Ich versuche es nochmal anders:
Gegeben sei diese Struktur:


Container C
	C.Name
	C.ID
	C.SubContainer	
		SubContainer SC
		SC.Name = SC1
		SC.ID
		SC.[...]
		SC.SubContainerEigenschaftenListe<SubContainerEigenschaft>
		
			SubContainerEigenschaft SCE_Name
			SCE.Wert
			SCE.[...]
			SCE.SubContainerEigenschaftDeffinitionsListe<SubContainerEigenschaftDeffinition>
				
				SubContainerEigenschaftDeffinition SCED
				SCED.Typ = String
				
			SubContainerEigenschaft SCE_Datum
			SCE.Wert
			SCE.[...]
			SCE.SubContainerEigenschaftDeffinitionsListe<SubContainerEigenschaftDeffinition>
				
				SubContainerEigenschaftDeffinition SCED
				SCED.Typ = Date
				
			SubContainerEigenschaft SCE_Ergebnis
			SCE.Wert
			SCE.[...]
			SCE.SubContainerEigenschaftDeffinitionsListe<SubContainerEigenschaftDeffinition>
				
				SubContainerEigenschaftDeffinition SCED
				SCED.Typ = Double
				
		SubContainer SC
		SC.Name = SC2
		SC.ID
		SC.[...]
		SC.SubContainerEigenschaftenListe<SubContainerEigenschaft>
		
			SubContainerEigenschaft SCE_Name
			SCE.Wert
			SCE.[...]
			SCE.SubContainerEigenschaftDeffinitionsListe<SubContainerEigenschaftDeffinition>
				
				SubContainerEigenschaftDeffinition SCED
				SCED.Typ = String
				
			SubContainerEigenschaft SCE_Datum
			SCE.Wert
			SCE.[...]
			SCE.SubContainerEigenschaftDeffinitionsListe<SubContainerEigenschaftDeffinition>
				
				SubContainerEigenschaftDeffinition SCED
				SCED.Typ = Date
				
			SubContainerEigenschaft SCE_Ergebnis
			SCE.Wert
			SCE.[...]
			SCE.SubContainerEigenschaftDeffinitionsListe<SubContainerEigenschaftDeffinition>
				
				SubContainerEigenschaftDeffinition SCED
				SCED.Typ = Double
				
			[usw]	




Wie komme ich möglichst flexibel an die SubContainerEigenschaft Name des Elementes SC2, ohne die gesammte Kette iterieren zu müssen?

16.806 Beiträge seit 2008
vor 5 Jahren

Also egal was Du machst: hellsehen wird Dein Code auch nicht können.
Die Eierlegende-Wollmilchsau gibts nicht 😉

Du kannst Dir natürlich eine Reflection Methode bauen, damit Du zB schreiben kannst
MyReflectionMethods.GetPropValue("SubContainers.Name", "SC2")
Ist dann einfach - aber halt nicht flexibel.

Ansonsten würde ich mir eben ganz simpel ein paar Erweiterungsmethoden bauen, die das für mich abstrahieren.
Kann man super über funktionale Umsetzung, Expression Tree und Co mit wenig Code umsetzen.

Ich hab aktuell was ähnliches vor mir; geht um Produktionsanlagen, die Produktionslinien haben, und darin wiederum Maschinen, deren Bauteile und Eigenschaften.
Also auch eine "tiefere Hierarchie" - aber da ist ganz simpel eine Schleife drüber auf Linq-Basis bzw. die Dictionaries für den Direktzugriff.
Reicht völlig aus, ist sauber testbar und für jeden ohne Black Magic erweiter/wartbar.