2009-04-01 8 views
1

Was ist der beste Weg, eine Strategie für den Konstruktor einer Vorlage/abstrakten Klasse in C# zu implementieren? Ich habe mehrere Klassen, die alle auf der Analyse einer Zeichenfolge im Konstruktor basieren. Das Parsen erfolgt in einer statischen Methode, die eine Liste von Schlüsselwertpaaren erstellt und allen Klassen gemeinsam ist, aber einige Felder sind auch für alle Klassen üblich - daher verwende ich eine abstrakte Template-Klasse.Implementieren einer Strategie für den Konstruktor

Das Problem ist, dass ich keine Möglichkeit sehe, die Implementierung des Konstruktors der abstrakten Basisklasse zu erben. Andernfalls würde ich die Konstruktorstrategie in der Basisklasse implementieren und die Handhabung der Listen in einigen abstrakten Methoden erzwingen.

Edit: Added Problem Code für die Template-Klasse

public abstract class XXXMessageTemplate 
{ 
    public XXXMessageTemplate(string x) // implementation for the constructor 
    { 
     Parse(x);//general parse function 
     CommonFields();//filling common properties 
     HandlePrivateProperties();//fill individual properties 
     HandlePrivateStructures();//fill individual structures 
    } 
    abstract void HandlePrivateProperties(); 
    abstract void HandlePrivateStructures(); 
} 

The actual messages should not implement any constructor and only implement the HandlePrivateProperties and HandlePrivateStructures functions. 

Antwort

7

Wenn Sie die Logik des Basisklassenkonstruktor laufen in der abgeleiteten Klasse wollen, sollten Sie in der Regel nur um es aufrufen:

public Derived(...) : base(...) 
{ 
    // ... 
} 

die Basisklasse können Aufruf abstrakt/virtuelle Methoden während des Konstruktor, aber es in der Regel verpönt ist, als die Konstruktorrumpf der abgeleiteten Klasse wird noch nicht ausgeführt worden ist. (Sie möchten dies wirklich nachdrücklich dokumentieren.)

Beantwortet das Ihre Frage? Ich bin mir nicht ganz sicher, ob ich das Problem verstehe - ein Pseudo-Code würde helfen.

EDIT: Die abgeleiteten Klassen haben, um Konstruktoren zu implementieren. Konstruktoren werden nicht vererbt. Wenn Sie keinen Konstruktor angeben, stellt der Compiler einen parameterlosen Konstruktor bereit, der einen parameterlosen Basiskonstruktor aufruft. Sie können jedoch leicht einen Konstruktor mit der gleichen Signatur schreiben und nur die Basisklasse Konstruktor aufrufen:

public Derived(string x) : base(x) 
{ 
    // Base constructor will do all the work 
} 
+0

Ich habe ein Pseudo-Code hinzugefügt, um den Emittenten sauberer zu machen ... – weismat

+0

O k - das bedeutet, dass meine Intension unmöglich ist, das Strategie-Muster hier zu erzwingen - ich muss dann einen Konstruktor implementieren, der einen geschützten Funktionsnamen-Konstruktor aufruft, der dann die Handle-Funktionen aufruft. Erinnert mich an die Einschränkung, dass ein Konstruktor kein anderes Konstrukt einer Klasse aufrufen kann. – weismat

+0

Konstruktoren können Konstruktoren anderer Klassen aufrufen - Sie können beispielsweise "object o = new object()" schreiben. Sie können nicht versuchen, einen anderen Konstruktor als Teil Ihrer eigenen Konstruktorkette zu verwenden - das wäre nicht sehr sinnvoll. –

2

einen Konstruktor für die Basisklasse und IT in den abgeleiteten Klassen verwenden:

abstract class Base { 
    // ... 
    protected Base(string commonField) { 
     CommonField = commonField; 
    } 
} 

class Derived1 : Base { 
    public Derived1(string commonField, string specificField) : base(commonField) { 
     SpecificField = specificField; 
    } 
} 
1

I bin nicht 100% sicher, dass ich die Frage vollständig verstanden habe, aber meinst du, dass deine Unterklassen eine literale Zeichenfolge an die Basis übergeben sollen, wie in diesem Beispiel?

public class MyMessage : XXXMessageTemplate 
{ 
    public MyMessage() : base("MyMessage String") 
    { 
    } 

    public override void HandlePrivateProperties() 
    { 
     // ... 
    } 

    public override void HandlePrivateStructures() 
    { 
     // ... 
    } 
} 
1

Wie ich sehen kann, ist das Problem in Parse (...) Methode. Nicht in der Methode selbst, sondern in seiner Existenz. Sie haben einige Rohdaten (String x), die vor der Verwendung in konstruierte Daten (Schlüsselwertpaare) konvertiert werden müssen, um Objekte zu konstruieren. Sie müssen also strukturierte Daten irgendwie in Basis- und Kindkonstruktoren übergeben. Ich sehe drei Ansätze:

  1. Analysieren Sie Daten in der Basisklasse und verwenden Sie die Eigenschaft protected base, um sie an childs zu übergeben.
  2. Analysieren Sie Daten vor dem Aufruf von Konstruktor.
  3. Parse Daten anstelle der Verwendung.

Sie können eine Antwort Mehrdad über zusätzliche geschützte Eigenschaft erweitern, die analysiert args hält.Etwas wie:

abstract class Base { 
    protected ParsedData ParsedData; 
    // ... 
    protected Base(string x) { 
     ParsedData = Parse(x); 
     CommonFields(); //initialize common fields using ParsedData 
    } 
} 

class Derived1 : Base { 
    public Derived1(string x) : base(x) { 
     DerivedFields(); //initialize specific fields using ParsedData 
    } 
} 

Oder Sie können im Voraus analysiert Zeichenfolge in Konstruktor übergeben:

abstract class Base { 
    protected ParsedData ParsedData; 
    // ... 
    public static ParsedData Parse(string x) 
    { 
     //Parse x here... 
    } 

    protected Base(ParsedData data) { 
     CommonFields(data); //initialize common fields using data 
    } 
} 

class Derived1 : Base { 
    public Derived1(ParsedData data) : base(data) { 
     DerivedFields(data); //initialize specific fields using data 
    } 
} 

oder anstelle der Nutzung analysieren:

abstract class Base { 
    // ... 
    protected Base(string x) { 
     var data = Parse(x); 
     CommonFields(data); //initialize common fields using data 
    } 
} 

class Derived1 : Base { 
    public Derived1(string x) : base(x) { 
     var data = Parse(x); 
     DerivedFields(data); //initialize specific fields using data 
    } 
} 
+0

Interessanter Ansatz - die Parse-Methode befindet sich derzeit in der Basisklasse und das resultierende Objekt wird nicht beibehalten - bis zu einem gewissen Grad auch aufgrund von Speicherbeschränkungen. Ich bin überrascht, dass Sie die Parse-Funktion als Problem dämpfen, aber es klingt logisch. – weismat

+0

Entschuldigen Sie, Methode # 1 Nachteil zu erwähnen: geparste Daten bleiben bis Objekt GCed. Es gibt auch keine einfache Möglichkeit, dieses Feld zu löschen, weil Sie bei einem bestimmten Konstruktor nicht wissen, ob ein anderes Kind existiert oder nicht. – Aleksei