Angenommen, ich habe eine Hierarchie von Item
Klassen : Rectangle, Circle, Triangle
. Ich möchte sie zeichnen können, daher besteht meine erste Möglichkeit darin Draw()
, jedem eine virtuelle Methode hinzuzufügen :
class Item {
public:
virtual ~Item();
virtual void Draw() =0;
};
Ich möchte jedoch die Zeichnungsfunktionalität in eine separate Zeichnungsbibliothek aufteilen, während die Kernbibliothek nur die grundlegenden Darstellungen enthält. Ich kann mir einige Möglichkeiten vorstellen:
1 - A DrawManager
, das eine Liste von Item
s erstellt und verwenden muss dynamic_cast<>
, um herauszufinden, was zu tun ist:
class DrawManager {
void draw(ItemList& items) {
FOREACH(Item* item, items) {
if (dynamic_cast<Rectangle*>(item)) {
drawRectangle();
} else if (dynamic_cast<Circle*>(item)) {
drawCircle();
} ....
}
}
};
Dies ist nicht ideal, da es auf RTTI basiert und eine Klasse dazu zwingt, alle Elemente in der Hierarchie zu kennen.
2 - Der andere Ansatz besteht darin, die Zeichnungsverantwortung auf eine ItemDrawer
Hierarchie ( RectangleDrawer
usw.) zu verschieben:
class Item {
virtual Drawer* GetDrawer() =0;
}
class Rectangle : public Item {
public:
virtual Drawer* GetDrawer() {return new RectangleDrawer(this); }
}
Dadurch wird die Trennung von Bedenken zwischen der Basisdarstellung der Elemente und dem Code zum Zeichnen erreicht. Das Problem ist jedoch, dass die Elementklassen von den Zeichnungsklassen abhängig sind.
Wie kann ich diesen Zeichnungscode in eine separate Bibliothek aufteilen? Ist die Lösung für die Artikel, eine Factory-Klasse mit einer Beschreibung zurückzugeben? Wie kann dies jedoch definiert werden, damit die Core-Bibliothek nicht von der Draw-Bibliothek abhängig ist?
quelle
visit()
Methode implementieren muss .Die von Ihnen beschriebene Aufteilung in zwei parallele Hierarchien ist im Wesentlichen das Brückenmuster .
Sie befürchten, dass die verfeinerte Abstraktion (Rectangle usw.) von der Implementierung (RectangleDrawer ) abhängt , aber ich bin mir nicht sicher, wie Sie dies vollständig vermeiden können.
Sie können sicherlich eine abstrakte Factory bereitstellen, um diese Abhängigkeit zu lösen, aber Sie müssen der Factory noch eine Möglichkeit mitteilen, welche Unterklasse erstellt werden soll, und diese Unterklasse hängt immer noch von der spezifischen verfeinerten Implementierung ab. Das heißt, auch wenn Rectangle nicht von RectangleDrawer abhängt, muss die Fabrik angewiesen werden, einen zu bauen, und RectangleDrawer selbst hängt immer noch von Rectangle ab.
Es lohnt sich auch zu fragen, ob dies eine nützliche Abstraktion ist. Ist das Zeichnen eines Rechtecks so schwierig, dass es sich lohnt, eine andere Klasse einzuordnen, oder versuchen Sie wirklich, die Grafikbibliothek zu abstrahieren?
quelle
RectangleDrawer
,CircleDrawer
usw. nicht der nützlichste Weg zu abstrahieren der Grafikbibliothek sein kann. Wenn Sie stattdessen eine Reihe von Grundelementen über eine reguläre abstrakte Schnittstelle verfügbar machen, wird die Abhängigkeit trotzdem aufgehoben.Schauen Sie sich die Wertesemantik und den auf Konzepten basierenden Polymorphismus an .
Diese Arbeit hat meine Sicht auf Polymorphismus verändert. Wir haben dieses System in wiederholten Situationen sehr effektiv eingesetzt.
quelle
Der Grund, warum Sie ein Problem haben, ist, dass Objekte sich nicht selbst zeichnen sollten. Etwas richtig zu zeichnen hängt von einer Milliarde Staatsstücken ab, und ein Rechteck wird keines dieser Teile haben. Sie sollten ein zentrales grafisches Objekt haben, das den Kernzustand wie Backbuffer / Tiefenpuffer / Shader / etc darstellt, und ihm dann eine Draw () -Methode geben.
quelle
Dog
oderCat
- das Objekt, das für das Zeichnen verantwortlich ist, ist viel komplexer als das Zeichnen eines Rechtecks.