1. Oktober 20223 j Hallo zusammen, ich bin gerade dabei einen kleinen Haushaltsrechner zu erstellen (fĂŒr den privaten Gebrauch). Da ich in diesem Programm einige Techniken verarbeiten möchte, mit denen ich noch nicht so vertraut bin, habe ich mir zum Ziel gesetzt Delegtaen, Linq, SQL u.s.w. in dieses Projekt einflieĂen zu lassen. Derzeit mache ich mich daran mein Wissen ĂŒber delegates etwas zu festigen und natĂŒrlich auch zu erweitern. Mittels einem MenĂŒ soll der Benutzer ĂŒber ein switch statement diverse Methoden in einer anderen Klasse aufrufen können (man könnte diese auch direkt angeben, allerdings hĂ€tte ich gerne einen Delegaten). Bei diesen Methoden handelt es sich um die Verarbeitung der Einzahlung, Auszahlung, KontoĂŒbersicht, Kontowechsel u.s.w. FĂŒr diese Auswahlmöglichkeit möchte ich einen Delegaten nutzen. Dabei stoĂe ich auf ein kleines Problem. Die Methode KontoĂŒbersicht benötigt keine Variable zur Verarbeitung, da diese ja nur auf ein Dictionary mit den einzelnen Transaktionen zugreifen und diese dann natĂŒrlich auch gegliedert ausgeben soll. Die Methoden Aus- und Einzahlung dagegen, benötigen allerdings verschiedene Variablen. Einmal eine Beschreibung der Transaktion und zusĂ€tzlich natĂŒrlich auch den dazugehörigen Wert der Transaktion. Nachdem was ich jetzt ĂŒber Delegaten weis, mĂŒsste ich theoretisch 2 verschiedene Delegaten nutzen. Einen fĂŒr die Ăbersicht ohne Parameter und einen fĂŒr die anderen Methoden mit Parameter. Diese Variante fĂ€nde ich allerdings recht unschön, da ich gerne einen fĂŒr alle nutzen wĂŒrde. Somit kommen wir zu meiner Frage, ob es möglich ist, einen Delegaten so flexibel zu konstruieren um ihm die Möglichkeit zu geben auf die verscheidenen Situationen zu reagieren. Ăhnlich wie eine Klasse mit mehreren Konstruktoren z.B. Auch wenn ich denke das meine Frage relativ klar ist, habe ich das Programm als rar Datei mit hochgeladen. Dieses ist allerdings noch ziemlich unfertig und hĂ€lt sich derzeit auch an keine Konventionen. hierbei handelt es sich wirklich um einen Rohling, welcher spĂ€ter noch komplett ĂŒberarbreitet werden muss. (Nur fĂŒr den Fall der FĂ€lle đ) Mit freundlichen GrĂŒĂen Gewinde Â
1. Oktober 20223 j Autor Hallo zusammen, also ich habe meine Antwort bekommen, auch hier im Forum. Man sollte sich auch mal mit der asuchfunktion beschĂ€ftigen. đ konnte es unter Delegaten ĂŒberladen finden. đ
1. Oktober 20223 j vor 10 Stunden schrieb Gewinde: Mittels einem MenĂŒ soll der Benutzer ĂŒber ein switch statement diverse Methoden in einer anderen Klasse aufrufen können (man könnte diese auch direkt angeben, allerdings hĂ€tte ich gerne einen Delegaten). Bei diesen Methoden handelt es sich um die Verarbeitung der Einzahlung, Auszahlung, KontoĂŒbersicht, Kontowechsel u.s.w. Keine Ahnung, wie du es umgesetzt hast aber im Grunde ist dies das Command-Pattern. vor 10 Stunden schrieb Gewinde: FĂŒr diese Auswahlmöglichkeit möchte ich einen Delegaten nutzen. Dabei stoĂe ich auf ein kleines Problem. Die Methode KontoĂŒbersicht benötigt keine Variable zur Verarbeitung, da diese ja nur auf ein Dictionary mit den einzelnen Transaktionen zugreifen und diese dann natĂŒrlich auch gegliedert ausgeben soll. Schaue dir dazu das Factory-Pattern an. FĂŒr das, was du tust, wĂŒrde ich einen Delegaten nicht empfehlen. Delegaten sind Funktionszeiger, die man aus der prozeduralen Welt kennt. Wenn du dann eh eine Switch-Anweisung verwendest, welche Methode nun aufgerufen werden soll, kannst du auch gleich das Factory-Pattern verwenden. Im Grunde stellt ein Delegate eine AbhĂ€ngigkeit dar. Daher lieĂe sich ein Delegate auch klassisch ĂŒber ein Interface und konkrete Implementierungen lösen, was eher der Objektorientierung entspricht. Ein Delegate ist ja eine Referenz auf eine Methode und Methoden sind in Klassen definiert. Wenn du jetzt eine Klasse hast, in der alle Methoden drinnenstecken, die zum Delegate passen, dann verstöĂt dies gegen das Single-Responsibility-Principle und Open-Closed-Principle. Also anstatt: public class Foo { public delegate void FooDelegate(int x, int y); public void Do(int x, int y) => this.GetFooDelegate(x, y)?.Invoke(x, y); private FooDelegate GetFooDelegate(int x, int y) => x switch { 0 => this.Do0, 1 => this.Do1, _ => throw new NotImplementedException() }; private void Do0(int x, int y) => Console.WriteLine(x * y); private void Do1(int x, int y) => Console.WriteLine(x / y); } Kann man es so schreiben: public interface IDo { void Do(int x, int y); } public class Foo { private readonly DoFactory _doFactory = new(); public void Do(int x, int y) => _doFactory.Create(x, y).Do(x, y); } public class DoFactory { public IDo Create(int x, int y) => x switch { 0 => new Do0(), 1 => new Do1(), _ => throw new NotImplementedException() }; } public class Do0 : IDo { public void Do(int x, int y) => Console.WriteLine(x * y); } public class Do1 : IDo { public void Do(int x, int y) => Console.WriteLine(x / y); } Sieht im ersten Moment vielleicht nach mehr Code aus aber jetzt kann man alles isoliert von einander testen. Zwar verstöĂt die Factory immer noch das Open-Closed-Principle aber irgendwelche Tode muss man sterben aber da gibt es auch andere Mittel und Wege. Im oberen Beispiel sind nĂ€mlich die einzelnen Implementierungen der Aufgaben privat. D.h. man kann sie nicht einzeln testen. Dies geht nur ĂŒber einen Umweg ĂŒber die Do()-Methode, was die Tests fĂŒr diese Methode komplexer und fehleranfĂ€lliger machen, da man implizit auch GetFooDelegate() mittesten muss. Die Klasse hat also gleich mehrere ZustĂ€ndigkeiten: Sie entscheidet, welche Aufgabe gemacht werden soll und sie implementiert die Aufgaben. Wenn man jetzt ĂŒberlegt, dass jede Aufgabe noch seine eigenen Klassenmitglieder hat, kann es sehr schnell unĂŒbersichtlich werden. Du schreibst ja selber, dass die einzelnen Aufgaben noch andere Informationen benötigen, die dann hier von der Klasse gehalten bzw. ermittelt werden mĂŒssen und somit noch mehr ZustĂ€ndigkeiten hat. Im unteren Beispiel sind sowie die einzelnen Aufgaben als auch die Entscheidung, was ausgefĂŒhrt werden soll, in separate Klassen eingeteilt, die einzeln getestet werden können. Jede Klasse hat ihre ZustĂ€ndigkeit und die Klasse Foo dient dann nur noch als Integration. Wenn man z.B. Do() von der Klasse Foo mit den Parametern (1, 1) aufruft, wird eine 1 auf dem Bildschirm ausgewiesen aber es ist im Grunde gar nicht so richtig klar, welche Aufgabe nun ausgefĂŒhrt wurde, da beide Aufgaben eine 1 ausgeben wĂŒrden (1 * 1 = 1 und 1 / 1 = 1). Im unteren Beispiel lieĂe sich aber ein Test fĂŒr die DoFactory-Klasse schreiben, mit dem wir testen können, dass die richtige Aufgabe gezogen wurde. In beiden Beispielen wĂŒrde er zwar 1 / 1 rechnen, aber vielleicht wollten wir 1 * 1 rechnen und unsere Factory hĂ€tte ein Fehler. Im oberen Beispiel lieĂe sich der Fehler nicht erkennen. Ich persönlich wĂŒrde Delegates nur verwenden, wenn ich optionale Aufgaben hĂ€tte, die eine Klasse ausfĂŒhren kann. Beispielsweise Logging- oder Debugging-Ausgaben, die ich von auĂen steuern und mir den Interface-Overhead sparen möchte. Events sind ja auch Delegates, wenn sie auch etwas speziell sind aber Events sind ja auch was optionales. Delegates werden gerne beim Passive-View MVP-Pattern verwendet, die im Grunde nur eine Weiterleitung der Events der Views darstellt. Ansonsten verzichte ich auf den Einsatz von Delegates.
Erstelle ein Konto oder melde dich an, um einen Kommentar zu schreiben.