abstract static-Methode bzw. abstrakter Konstruktor
-
Du willst den Benutzer doch zwingen, so eine Methode zu implementieren? Also verlang vom Benutzer ein Objekt, das die Methode implementiert!? Dann hast du eines, dessen Methode du aufrufen kannst...
-
Schauen wir doch mal...
interface A { void erzeuge(string s); } class B : A { private int var1; public B(int var) { this.var1=var; } void erzeuge(string s) { var1 = s.toInt(); } }
Ich möchte ein Objekt von der Klasse B erzeugen... wie mache ich das nun?
A a = new B();//ERROR: Es gibt keinen Standardkonsturkur(Soll es auch nicht geben, da var1 immer ein sinvollen Wert haben soll)
a.erzeuge("123");Oder so?
A a = new B(0);//Nicht gut: Warum muss ich eine 0 übergeben? Ich will doch B mit 123
a.erzeuge("123");
-
interface A { // whatever you want } interface Factory { A create(string s); } // Userseite class B : A { private int var1; public B(int var) { this.var1 = var; } // ... } class BFactory : Factory { public A create(string s) { return new B(s.toInt()); } }
-
Hm ok, also muss ich die create-Funktion auslagern. Ich darf sie also nicht mit bei meiner Klasse B lagern. Schade... ich hätte das gerne zusammen gehabt.
Wäre eine C#-Version mit abstraktem Konstruktor denkbar? Warum gibt es das nicht? Ich glaube nicht, dass das ein Zufall ist.
-
Nein, das ist kein Zufall. Was sollte ein abstrakter Konstruktor für einen Sinn haben? Richtig, die Antwort ist: Keinen. Um ein Objekt zu erzeugen, musst du dessen konkreten Typ kennen, das geht rein prinzipiell nicht anders...
-
Nehmen wir mal an das hier wäre erlaubt:
abstract class A { abstract A(string s); } class B: A { overide B(string s); } A a = new B("Hallo lieber dot^^");
An welcher Stelle ist das für den Compiler uneindeutig? Wo weiß er nicht weiter?
-
Was hättest du davon? Wenn du den Benutzer also nun zwingen kannst, für seine Typen einen bestimmten Konstruktor bereitzustellen, was tust du dann damit? Wie erfährt dein Code überhaupt von der Existenz dieser benutzerdefinerten Typen?
-
Nun, ich habe einerseits das hier:
abstract class A { abstract A(string s); } class B: A { overide B(string s){} } class C: A { overide C(string s){} }
Nun habe ich das noch das:
void leseDateiEin(string[] zeilen) { List<A> liste = new List<A>(); foreach (string s in zeilen) { if (s.StartsWith("B")) liste.Add(new B(s)); if (s.StartsWith("C")) liste.Add(new C(s)); } }
Das wäre dann mit abstrakten Konstruktoren möglich. Das will ich
-
Ok, ich bin jetzt ein Benutzer und mache einen weiteren Typ D. Wie erfährt leseDateiEin() davon und erzeugt nun meine D Objekte?
-
Hm... das geht dann wohl nicht. Verdammt aber auch, ich glaube dass ist nicht so einfach wie ich mir das gedacht habe.
Aber eins musst du doch zugeben. Meine Variante sieht schlanker aus, als die Fabrik-Muster-Variante. Also ein kleiner Gewinn wäre es schon. Ich wäre der Erste, der C#-Compiler mit abstrakten Konstruktoren nutzen würde
-
XMAMan_ schrieb:
Aber eins musst du doch zugeben. Meine Variante sieht schlanker aus, als die Fabrik-Muster-Variante. Also ein kleiner Gewinn wäre es schon. Ich wäre der Erste, der C#-Compiler mit abstrakten Konstruktoren nutzen würde
Deine Variante tut aber nicht was du willst und ein abstrakter Konstruktor ist immer noch sinnlos. In deinem Beispiel da oben brauchst du keinen abstrakten Konstruktor...
-
Wie waere es denn mit nem kleinen Dictionary, wo du als Schluessel die Buchstaben reinschreibst die "erlaubt" sind und als Value einfach einen Functor der die das Passende Objekt erzeugt. Etwa so:
Dictionary<string,Func<string,AbstracteKlasse>> creators = new Dictionary<string,Func<string,AbstracteKlasse>>(); creators.Add("B", (param) => new B()); creators.Add("C", (param) => new C()); List<AbstracteKlasse> liste = new List<AbstracteKlasse>(); // deine Einlese funktion, die muss natuerlich noch flexibler sein. aber das solltest du ja wissen. if(s.StartsWith("B")) && creators.Contains("B")) liste.Add(creators["B"]("irgendEinMistigerString"));
So das ganze kannst du jetzt noch in einer schoenen Factory verpacken(und ich denke darauf spielte dot eventuell ab) und fertig ist der Lack.
-
Wenn ich die vielen
if (s.StartsWith("B")) liste.Add(new B(s));
durch viele
creators.Add("B", (param) => new B());
ersetze, habe ich glaube nichts gewonnen. Das Auslagern von dieser "String"-"Datentyp"-Zuordnung in ein Dictonary hätte nur dann Sinn, wenn ich es noch an anderer Stelle brauche.
Mein Code soll einerseit so kurz(Wenig Variablen, Wenig Anweisungen) wie möglich sein, anderseits soll er so viel wie möglich gegen Unachtsamkeitsfehler geschützt sein. Ich weiß, die Anforderungen klingen Hart, aber mir gehts bei meinen Programm jetzt mal vorranig darum einfach nur Programmierprinzipien/Designpattern zu üben.
-
Factories sind Designpattern. Ob du das nun in eine Factory packst oder in ein Dictionary, an IRGENDEINER Stelle musst du konkrete Implementationen liefern. Und das kannst du nur indem du diese irgendwo definierst.
-
Ja, das habe ich momentan durch die vielen
if (s.StartsWith("B")) liste.Add(new B(s));
-Zeilen.
Ich möchte den Code nicht durch zusätzliche Variablen/Klassendefinitionen aufblähen.(Hat hier jemand übrigens Blähungen von euch?
)
-
XMAMan__ schrieb:
Ja, das habe ich momentan durch die vielen
if (s.StartsWith("B")) liste.Add(new B(s));
-Zeilen.
Ich möchte den Code nicht durch zusätzliche Variablen/Klassendefinitionen aufblähen.(Hat hier jemand übrigens Blähungen von euch?
)
Ja extreme.
Zurueck zum Thema:
Nun ja, die If sind ja ziemlich Wartungsunresistent. Wenn du eine Factory anbietest wo "jeder" seine Implementierungen registrieren kann und spaeter abrufen kann, uebergibst du die Verantwortung an denjenigen der deine Factory benutzt. Deine Aufgabe ist es nun die Rahmenbedingungen zu definieren. Das kannst du entweder ueber ein Interface machen, wie es dot bereits angemerkt hat. Oder du verpackst das erzeugen in einen Funktor der einen von dir definierten Rueckgabewert haben muss(wie z.B. eine Abstrakte Klasse, oder Interface). Alles andere ist Unsinn.