2008-08-28 8 views
9

Es tut mir leid, wenn meine Frage so lange und technisch ist, aber ich denke, es ist so wichtig, andere Menschen zu interessieren wird esEin allgemeineres Besuchermuster

ich nach einem Weg suchen, eindeutig einige Software-Interna trennen von ihre Darstellung in C++

ich eine generischen Parameter Klasse (später in einem Behälter aufbewahrt werden), die jede Art von Wert mit dem dem boost :: jede Klasse enthält

ich habe eine Basisklasse (grob) von dieser Art (natürlich gibt es mehr Zeug)

class Parameter 
{ 
public: 
    Parameter() 
    template typename<T> T GetValue() const { return any_cast<T>(_value); } 
    template typename<T> void SetValue(const T& value) { _value = value; } 
    string GetValueAsString() const = 0; 
    void SetValueFromString(const string& str) const = 0; 
private: 
    boost::any _value; 
} 

Es gibt zwei Ebenen von abgeleiteten Klassen: Die erste Ebene definiert den Typ und die Umwandlung zu/von string (zB ParameterInt oder ParameterString) Die zweite Ebene, das Verhalten und die reale Schöpfer (zum Beispiel definiert ParameterAnyInt Herleiten und ParameterLimitedInt von ParameterInt oder ParameterFilename von GenericString)

je nach realen Typ würde Ich mag externe Funktion oder Klassen hinzufügen, die auf den spezifischen Parameter je nach Typ arbeitet ohne virtuelle Methoden der Basisklasse hinzufügen und ohne fremde Abgüsse zu tun

Zum Beispiel würde ich wie die richtigen GUI-Controls in Abhängigkeit von Parametertypen zu erstellen:

Widget* CreateWidget(const Parameter& p) 

Natürlich kann ich nicht wirklich Parametertyp aus dieser verstehen, wenn ich RTTI verwenden oder es mich selbst implementieren (mit ENUM und Schaltergehäuse), aber dies ist nicht die richtige OOP-Designlösung, wissen Sie.

Die klassische Lösung ist das Visitor-Entwurfsmuster http://en.wikipedia.org/wiki/Visitor_pattern

Das Problem mit diesem Muster ist, dass ich im Voraus wissen, welche Arten abgeleitet werden umgesetzt, so (der Zusammenstellung, was in wikipedia und meinen Code geschrieben ist) wir Art haben:

struct Visitor 
{ 
    virtual void visit(ParameterLimitedInt& wheel) = 0; 
    virtual void visit(ParameterAnyInt& engine) = 0; 
    virtual void visit(ParameterFilename& body) = 0; 
}; 

gibt es eine Lösung für dieses Verhalten auf andere Weise im voraus alle konkreten Typen und ohne Ableitung des ursprünglichen Besucher zu wissen, ohne die Notwendigkeit zu erhalten?


Edit:Dr. Pizza's solution seems the closest to what I was thinking, aber das Problem ist immer noch die gleiche, und das Verfahren tatsächlich auf dynamic_cast setzt, dass ich als eine Art (auch wenn schwach) RTTI Methode

zu vermeiden versuche, Vielleicht ist es besser, an eine Lösung zu denken, ohne das Besuchermuster zu zitieren und unseren Geist zu reinigen. Der Zweck ist, die nur die Funktion so:

Widget* CreateWidget(const Parameter& p) 

verhalten sich anders für jeden „Beton“ Parameter ohne Informationen über seine Art zu verlieren

Antwort

0

Wenn ich das richtig verstehe ...

Wir hatten ein Objekt das könnte verschiedene Hardwareoptionen verwenden. Um dies zu erleichtern, verwendeten wir eine abstrakte Schnittstelle von Device. Das Gerät hatte eine Reihe von Funktionen, die bei bestimmten Ereignissen ausgelöst wurden.Die Verwendung wäre die gleiche, aber die verschiedenen Implementierungen des Geräts würden entweder eine vollständig ausgearbeitete Funktion haben oder einfach sofort zurückkehren. Um das Leben noch einfacher zu machen, waren die Funktionen leer und es gab Ausnahmen, wenn etwas schief ging.

1

Ich habe this ("azyklische Besucher") zu guter Wirkung verwendet; Es ermöglicht das Hinzufügen neuer Klassen zur Hierarchie, ohne die bestehenden zu ändern.

+0

Schade, dass dieser Artikel verschwunden zu sein scheint: er hat mein Interesse geweckt. Ich nehme an, acht Jahre sind eine Ewigkeit im Internet. – Nicole

+0

@Nicole http://web.archive.org/web/20080517124442/http://www.objectmentor.com/resources/articles/acv.pdf – DrPizza

+0

Vielen Dank! Das ist sehr nett. – Nicole

0

Aus Gründen der Vollständigkeit halber:

es ist natürlich durchaus möglich, eine eigene Implementierung einer Multimethode Zeigertabelle für Ihre Objekte und berechnen die Methode Adressen manuell während der Laufzeit zu schreiben. Es gibt eine paper von Stroustrup zum Thema der Implementierung von Multimethoden (wenn auch im Compiler).

Ich würde niemandem wirklich empfehlen, dies zu tun. Die Implementierung der Implementierung ist sehr kompliziert und die Syntax für die Verwendung ist wahrscheinlich sehr umständlich und fehleranfällig. Wenn alles andere fehlschlägt, könnte dies immer noch der richtige Weg sein.

0

Ich habe Probleme, Ihre Anforderungen zu verstehen. Aber Ill Zustand - in meinen eigenen Worten, wie sie waren - was ich verstehe die Situation zu sein:

  • Sie haben abstrakte Parameter-Klasse, die schließlich zu einigen konkreten Klassen Unterklassen (zB: ParameterLimitedInt).

  • Sie haben ein separates GUI-System, das diese Parameter in einer generischen Art und Weise übergeben wird, aber der Catch ist, dass es die GUI-Komponente für den konkreten Typ der Parameterklasse darstellen muss.

  • Die Einschränkungen sind, dass Sie nicht RTTID tun möchten, und nicht Code schreiben möchten, um alle möglichen Arten von konkreten Parameter zu behandeln.

  • Sie sind offen für die Verwendung des Besuchermusters.

Mit diesen Ansprüchen ist, hier ist, wie ich eine solche Situation umgehen würde:

Ich würde das Besuchermuster implementieren, wo die() gibt einen Booleschen Wert annehmen. Die Basisparameterklasse würde eine virtuelle accept() - Funktion implementieren und false zurückgeben.

Konkrete Implementierungen der Parameter-Klasse würden dann accept() - Funktionen enthalten, die den visit() aufrufen. Sie würden wieder wahr werden.

Der Besucher Klasse würde die Verwendung eines Templat-Besuch() Funktion, so dass Sie nur für die konkreten Parametertypen sorgen Sie Unterstützung außer Kraft setzen würde:

class Visitor 
{ 
public: 
    template< class T > void visit(const T& param) const 
    { 
    assert(false && "this parameter type not specialised in the visitor"); 
    } 
    void visit(const ParameterLimitedInt&) const; // specialised implementations... 
} 

Wenn also accept() false zurückgibt, wissen Sie, die Betontyp für den Parameter hat das Besuchermuster noch nicht implementiert (falls es zusätzliche Logik gibt, würden Sie es bevorzugen, von Fall zu Fall vorzugehen). Wenn das assert() im Besuchermuster ausgelöst wird, ist es, weil es keinen Parametertyp besucht, für den Sie eine Spezialisierung implementiert haben.

Ein Nachteil bei all dem ist, dass nicht unterstützte Besuche nur zur Laufzeit abgefangen werden.

Verwandte Themen