Laden...

Typenabhängige Ausführung von unterschiedlichen Klassen über Dictionary

Erstellt von MeisterPetz vor 6 Jahren Letzter Beitrag vor 6 Jahren 1.431 Views
M
MeisterPetz Themenstarter:in
2 Beiträge seit 2017
vor 6 Jahren
Typenabhängige Ausführung von unterschiedlichen Klassen über Dictionary
    class BuchBox : IBuchBox
    {
        public Dictionary<string, Buch> Buchmenge { get; private set; }
        public BuchBox(Dictionary<string, Buch> buchmenge)
        {
            this.Buchmenge = buchmenge;
        }
    }
    class ZeitschriftenBox
    {
        public Dictionary<string, Buch> Zeitschriftenmenge;
        public ZeitschriftenBox(Dictionary<string, Buch> zeitschriftenmenge)
        {
            this.Zeitschriftenmenge = zeitschriftenmenge;
        }
    }
    class MedienManager
    {
        IBuchBox buchstaender;
        IZeitschriftenBox zeitschriftenstaender;

        private Dictionary<string, object> verbinder;
		
		private Dictionary<string, Type> typenverbinder;

        public MedienManager(IZeitschriftenBox zeitschriftenstaender, IBuchBox buchstaender)
        {
            this.zeitschriftenstaender = zeitschriftenstaender;
            this.buchstaender = buchstaender;
            this.verbinder = new Dictionary<string, object>()
            {
                {"Buch", this.buchstaender },
                {"Zeitschrift", this.zeitschriftenstaender }
            };
			this.typenverbinder = new Dictionary<string, Type>()
			{
				{"Buch", typeof(IBuchBox)},
				{"Zeitschrift", typeof(IZeitschriftenBox)}
			};
        }

        public void SetzeInhalt(string art, string eigenschaft, string wert)
        {
			var medium = Convert.ChangeType(this.verbinder[art], this.typenverbinder[typ]);
			//trotzdem weiter vom Typ object
			medium.oeffnen();
			var seitenAnzahl = medium.GetType().GetProperty("SeitenAnzahl").GetValue(medium); 
			// medium wird als Typ erkannt und die jeweiligen Methoden/Properties sind nutzbar?
        }
    }

Hallo,
ich hoffe mir kann jemand weiterhelfen.
Ich habe oben die Definition einiger Klassen und der Interfaces weggelassen,
da sie sich denke mal aus den Kontex schließen lassen.

Hier die Frage:
Zeitschrift und Buch haben einige unterschiedliche Eigentschaften und
können nicht das selbe Interface nutzen(durch externes SDK nicht möglich).
Ich möchte natürlich nicht alle Funktionen von Buch(extern) in Buchbox
implementieren um sie über mit zu nutzen.

 Dictionary<string, Action<Delegate>> verbinder

Ziel ist dadurch einen Zugriffspunkt zu schaffen und den Zugriff auf das
SDK nicht überall im Code zu verteilen.

Sorry für das schlechte Beispiel 😉 Ich hoffe mir kann jemand weiterhelfen.
Gruß!

M
177 Beiträge seit 2009
vor 6 Jahren

Leider sehe ich die Frage nicht eindeutig.

Ich hätte aber gemeint du könntest evtl. was mit dem Adapter-Pattern anfangen.

Mit dem Dictionary kannst du dahingehend auch schon einiges machen.

Eine möglicher Ansatz wäre z.B:

Dictionary<Typ, IAdapter> _AdapterDictionary
_AdapterDictionary.Add(typeof(BookAmazonType),AdapterAmazon);
_AdapterDictionary.Add(typeof(BookStadtBibliothekType),AdapterStadtBibliothek);

Für jedes Interface das gewrappt werden muss erstellst du einen Adapter. Z.b. AdapterAmazon,AdapterStadtBibliothek,AdapterC... die IAdapter implementieren.

Im _AdapterDictionary hinterlegst du für jeden Typ die passende Adapterinstanz. Zugriff könnte dann so aussehen.

_AdapterDictionary[CustomTyp.GetType()].GetBook("");
P
1.090 Beiträge seit 2011
vor 6 Jahren

So genau habe ich jetzt auch nicht verstanden was du machen möchtest.
Für mich klingt es jetzt ein bisschen nach einen einfachen IoC-Container.

Tim Ross:Creating a Simple IoC Container

Sollte man mal gelesen haben:

Clean Code Developer
Entwurfsmuster
Anti-Pattern

3.003 Beiträge seit 2006
vor 6 Jahren

a) verstehe ich nicht, worin sich IZeitschriftenbox und IBuchBox unterscheiden. Außer in den Namen jetzt. Das ist nach meinem Verständnis EINE Klasse.

b) du beziehst dich auf Klassen "Buch" und "Zeitschrift", die in einem externen SDK deklariert sind. Okay, gut, aber in deinem Codebeispiel kommt "Zeitschrift" gar nicht vor. Was sollen wir also mit der Information anfangen?

c) so, wie da Dictionaries verwendet werden, und auch der "SetzeInhalt"-Methode nach zu urteilen, besteht an irgendeiner Stelle ein grundlegendes Missverständnis, was objektorientieres Programmieren angeht.

Ich kann hier nur raten: wenn dein Problem ist, dass du zwei Klassen hast, die nicht miteinander verwandt sind, aber diese beiden Klassen gern generisch gemeinsam verwalten möchtest, dann:

  • Schaffe ein gemeinsames Interface
  • schaffe zwei Wrapperklassen, die dieses Interface implementieren, und jeweils Buch und Zeitschrift wrappen
  • schaffe pro Wrapper vereinheitlichte Zugriffsmöglichkeiten auf Eigenschaften der gewrappten Objekte

(s.a. Facade-Pattern oder Proxy-Pattern oder Adapter-Pattern. Ich würde hier Facade bevorzugen.)

Dann kannst du zB eine allen gemeinsame Property "Seitenanzahl" einführen und direkt "SetzeInhalt" wegwerfen. (Und bitte, tu das. Reflection einzusetzen, um Architekturschwächen zu kompensieren, ist einfach nur bäh.)

LaTino
EDIT: @Palin: Kanone und Spatzen 😉

"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)

M
MeisterPetz Themenstarter:in
2 Beiträge seit 2017
vor 6 Jahren

Vielen Dank für die Antworten! Das Beispiel war wirklich schlecht gewählt und meine Problematik auch schlecht beschrieben, Entschuldigung dafür.
Ok hier die richtige Aufgabenstellung/Problemstellung:
Ich nutze die Baumer GAPI SDK um eine Ansteuerung für eine GeniCam Kamera zu bauen(also Bachelorarbeit). Die SDK hat einige Hauptklassen mit Methoden und Properties zum Beispiel:
System, Interface, Device.
Für jede dieser Klassen habe ich eine Wrapper-Klassen mit dem Inhalt:

Dictionary<string, System> systemRelation{get; private set;} // string =  Id

Diese werden Unity Container verwaltet (so vorgeschrieben).

Für jede gewrappte Klasse wird auch eine "Fassade"-Klasse erstellt:
Diese implementiert alle gebrauchte Funktionalität der originalen Klasse.


    public class GenTlSystem
    {
        private readonly ISystemWrapper systemWrapper;

        public GenTlSystem(ISystemWrapper systemWrapper, string id)
        {
            this.systemWrapper = systemWrapper;
            this.Id = id;
        }

        public string Id { get; private set; }

        public void Close()
        {
                this.systemWrapper.SystemRelation.FirstOrDefault(n =>n.Key.Equals(this.Id)).Value.Close();    
        }

        public void Open()
        {
                this.systemWrapper.SystemRelation.FirstOrDefault(n =>n.Key.Equals(this.Id)).Value.Open();        
        }
         public void SetValue(string node, object newValue)
         {
           this.systemWrapper.SystemRelation.FirstOrDefault(n =>n.Key.Equals(this.Id)).Value. RemoteNodeList[node].value = newValue;
          }

    }

Diese Lösung funktioniert schon so, aber fühlt sich nicht sehr elegant an da Funktionen wie Open und SetValue für jede wieder implementiert werden muss.
Ziel wäre einen WrapperContainer zu erstellen, der alle Wrapper verwaltet und mit nur einer Linq Funktion die jeweiligen Objekte typunabhängig aufruft und die gewünschte Funktion ausführt in Form von:

wrapperContainer.Open( "System", "SystemId" );
wrapperContainer.SetValue("System", "SystemId", "FileName", "C://usw") 

Für das setzen der Werte habe ich ein Strategiemuster was abhängig des Typs umwandelt.

Gibt es eine effizientere und elegantere Lösungen?
Schonmal danke für die Hilfe und ein schönes Wochenende!
Gruß!