seit geraumer Zeit habe ich an einer Anwendung gearbeitet. Da Programmierung nur ein Hobby ist, geht dieses Projekt schon viel zu lange, aber das ist nebensächlich. Ich bin jetzt an einem Punkt, wo jedes "Problem" furchtbar schwer zu lösen ist. Und ich denke daran, den Code zu refactoring, aber das würde zu einem "vollständigen" Neuschreiben führen.Programmierungsparadigma; frage mich, ob Neuschreiben/Refactoring notwendig ist
Lassen Sie mich das Problem erklären, und wie ich es gerade gelöst habe. Im Grunde habe ich Daten, und ich lasse Dinge über diese Daten geschehen (gut beschrieben ich über jedes Programm nicht ich?). Was passiert ist:
Daten -> Viewer zeigt Daten auf aktuellen Daten basieren Betrachter Benutzereingabe zurück - -> Viewer angezeigt werden, fragt> Daten -> fragt „Vollstrecker“, um sie auszuführen -> neue Daten
Jetzt verwendet, um dieses sehr gut zu arbeiten, und ich dachte ursprünglich: „hey, ich könnte zum Beispiel ändern Eingabeaufforderung durch qt oder Fenster - oder sogar nehmen, dass externe (C#) und einfach dieses Programm aufrufen“ .
Aber als das Programm wuchs, wurde es mehr und mehr ermüdend. Am wichtigsten ist, dass die Daten auf unterschiedliche Weise angezeigt werden, je nachdem, um welche Daten es sich handelt und - was noch wichtiger ist - wo sie sich befinden. Also ging ich zurück zum Baum & hinzugefügt irgendwie zu "verfolgen", was die Elternlinie ist. "Dann würde der allgemeine Viewer nach dem spezifischsten tatsächlichen Widget suchen. Es verwendet hat eine Liste mit [Standort; Widget] Werte und findet den am besten passenden Ort
Die Probleme beginnen beim Update auf neue "Daten" - ich muss alle Assets durchsehen - Viewer, Saver etc etc .. Die Aktualisierung des Check-Mechanismus hat mir viele Fehler eingebracht wie "hey warum zeigt es das falsche Widget jetzt wieder an?".
Jetzt kann ich das komplett umtauschen. Und anstelle der Baumstruktur, die zu einem generischen Viewer aufruft, würde ich OO "interne" Baumfunktionen verwenden Knoten wären childs (& whe Wenn ein neuer Viewer oder Speichermechanismus benötigt wird, wird ein neues Kind gebildet.
Dies würde den schwierigen Prüfmechanismus entfernen, wo ich die Position in der Struktur überprüfe. Es könnte jedoch eine ganze andere Dose Würmer eröffnen. Und ich hätte gerne ein paar Kommentare dazu? Soll ich den Zuschauer komplett getrennt halten - Schwierigkeiten bei der Datenprüfung? Oder ist der neue Ansatz besser, kombiniert er doch Daten & Ausführung in einem einzigen Knoten. (Also, wenn ich wünsche von qt zu ändern cli/C# zu sagen, dass es fast unmöglich wird)
Welche Methode soll ich am Ende zu verfolgen? Kann ich noch etwas anderes machen? Um den Viewer getrennt zu halten und dennoch zu verhindern, dass Sie überprüfen müssen, welches Widget angezeigt werden soll?
EDIT, nur um etwas "Code" zu zeigen und wie mein Programm funktioniert. Ich bin mir nicht sicher, ob das gut ist, wie ich schon sagte, es ist zu einem Haufen von Methoden geworden.
Es ist beabsichtigt, mehrere "gamemaker projekte" zusammen zu verschmelzen (wie GM: Studio merkwürdig fehlt diese Eigenschaft). Gamemaker-Projektdateien sind einfach Gruppen von XML-Dateien. (Haupt-XML-Datei mit nur Links zu anderen XML-Dateien und eine XML-Datei für jede Ressource - Objekt, Sprite, Sound, Raum usw.).Es gibt jedoch einige "Macken", die es nicht wirklich möglich machen, mit Boost-Eigenschaften-Bäumen oder qt zu lesen: 1) Die Reihenfolge der Attribute/Kind-Knoten ist in bestimmten Teilen der Dateien sehr wichtig. und 2) Leerzeichen wird oft ignoriert, aber an anderen Stellen ist es sehr wichtig, es zu bewahren.
Das heißt, es gibt auch viele Punkte, wo der Knoten genau gleich ist. Wie ein Hintergrund <width>200</width>
haben kann und ein Raum kann auch haben. Für den Benutzer ist es jedoch sehr wichtig, über welche Breite er spricht.
Anyways, so dass die "allgemeine viewer" (AskGUIFn) hat folgende typedefs zu handhaben:
typedef int (AskGUIFn::*MemberFn)(const GMProject::pTree& tOut, const GMProject::pTree& tIn, int) const;
typedef std::vector<std::pair<boost::regex, MemberFn> > DisplaySubMap_Ty;
typedef std::map<RESOURCE_TYPES, std::pair<DisplaySubMap_Ty, MemberFn> > DisplayMap_Ty;
Wo "GMProject :: ptree" ist ein Baumknoten, RESOURCE_TYPES ist eine konstante Spur zu halten Welche Art von Ressource bin ich im Moment (Sprite, Objekt usw.). Das "memberFn" wird hier einfach etwas sein, was ein Widget lädt. (Obwohl AskGUIFn natürlich nicht der einzige allgemeine Viewer ist, wird dieser nur geöffnet, wenn andere "automatische" Überschreib-, Überspring-, Umbenennungs-Handler fehlgeschlagen sind).
nun zu zeigen, wie diese Karten initialisiert werden (alles im Namensraum „MW“ ist eine qt-Widget):
AskGUIFn::DisplayMap_Ty AskGUIFn::DisplayFunctionMap_INIT() {
DisplayMap_Ty t;
DisplaySubMap_Ty tmp;
tmp.push_back(std::pair<boost::regex, AskGUIFn::MemberFn> (boost::regex("^instances "), &AskGUIFn::ExecuteFn<MW::RoomInstanceDialog>));
tmp.push_back(std::pair<boost::regex, AskGUIFn::MemberFn> (boost::regex("^code $"), &AskGUIFn::ExecuteFn<MW::RoomStringDialog>));
tmp.push_back(std::pair<boost::regex, AskGUIFn::MemberFn> (boost::regex("^(isometric|persistent|showcolour|enableViews|clearViewBackground) $"), &AskGUIFn::ExecuteFn<MW::ResourceBoolDialog>));
//etc etc etc
t[RT_ROOM] = std::pair<DisplaySubMap_Ty, MemberFn> (tmp, &AskGUIFn::ExecuteFn<MW::RoomStdDialog>);
tmp.clear();
//repeat above
t[RT_SPRITE] = std::pair<DisplaySubMap_Ty, MemberFn>(tmp, &AskGUIFn::ExecuteFn<MW::RoomStdDialog>);
//for each resource type.
Dann, wenn der Baum Datenstruktur des allgemeinen Betrachter sagt es der Betrachter das ausführt angezeigt werden möge folgende Funktion:
AskGUIFn::MemberFn AskGUIFn::FindFirstMatch() const {
auto map_loc(DisplayFunctionMap.find(res_type));
if (map_loc != DisplayFunctionMap.end()) {
std::string stack(CallStackSerialize());
for (auto iter(map_loc->second.first.begin()); iter != map_loc->second.first.end(); ++iter) {
if (boost::regex_search(stack, iter->first)) {
return iter->second;
}
}
return map_loc->second.second;
}
return BackupScreen;
}
Und das ist, wo die Probleme offen zu sein begann. Die Funktion CallStackSerialize()
hängt von einem Call-Stack ab. Dieser Call_stack wird jedoch in einem "Handler" gespeichert. Ich habe es dort gespeichert, weil alles von einem Handler beginnt. Ich bin mir nicht wirklich sicher, wo ich diesen "call_stack" speichern soll. Stellen Sie ein anderes Objekt vor, das verfolgt, was vor sich geht? Ich habe versucht, die Route zu gehen, wo ich die Eltern mit dem Knoten selbst speichern. (Verhindern der Notwendigkeit eines Call-Stack). Aber das lief nicht so gut wie ich es wollte: Jeder Knoten hat einfach einen Vektor, der seine Kindknoten enthält. Das Verwenden von Zeigern ist also nicht möglich, um auf die Eltern-Notiz zu zeigen ... (PS: vielleicht sollte ich das in einer anderen Frage reformieren ..)
+1, für die Zahlen. Ohne die Frage zu lesen, sieht es einfach cool aus. – iammilind
Kennen Sie den "[Inner Platform Effect] (http://en.wikipedia.org/wiki/Inner_platform_effect)"? Ich verstehe dein Problem nicht gut genug, um irgendwelche Schlüsse zu ziehen (und ich weiß natürlich nichts über deine Bewerbung!), Aber wenn du mit dem Begriff nicht vertraut bist, ist es ein bisschen Forschung wert. Schwierigkeiten, ein sehr komplexes System zu modifizieren, das ein Super-Allzweck-Framework sein soll, klingt wie ein Symptom dieses bestimmten Antipatterns ... – Rook
ist es nicht, dass Ihre Datenknoten tatsächlich eine Art Profil benötigen, wenn sie erstellt werden, beschreibt das Profil wie um sie zu präsentieren, zu handeln und zu retten? – armel