Disons que j'ai une hiérarchie de Item
cours: Rectangle, Circle, Triangle
. Je veux pouvoir les dessiner, donc ma première possibilité est d'ajouter une Draw()
méthode virtuelle à chacun:
class Item {
public:
virtual ~Item();
virtual void Draw() =0;
};
Cependant, je souhaite diviser la fonctionnalité de dessin en une bibliothèque Draw distincte tandis que la bibliothèque Core ne contient que les représentations de base. Il y a quelques possibilités auxquelles je peux penser:
1 - A DrawManager
qui prend une liste de Item
s et doit utiliser dynamic_cast<>
pour déterminer quoi faire:
class DrawManager {
void draw(ItemList& items) {
FOREACH(Item* item, items) {
if (dynamic_cast<Rectangle*>(item)) {
drawRectangle();
} else if (dynamic_cast<Circle*>(item)) {
drawCircle();
} ....
}
}
};
Ce n'est pas idéal car il repose sur RTTI et force une classe à être au courant de tous les éléments de la hiérarchie.
2 - L'autre approche consiste à reporter l'attribution de la responsabilité à une ItemDrawer
hiérarchie ( RectangleDrawer
, etc.):
class Item {
virtual Drawer* GetDrawer() =0;
}
class Rectangle : public Item {
public:
virtual Drawer* GetDrawer() {return new RectangleDrawer(this); }
}
Cela permet de séparer les préoccupations entre la représentation de base des articles et le code de dessin. Le problème est que les classes d'objets dépendent des classes de dessin.
Comment puis-je séparer ce code de dessin dans une bibliothèque distincte? La solution consiste-t-elle pour les articles à renvoyer une classe d'usine d'une certaine description? Cependant, comment cela peut-il être défini afin que la bibliothèque Core ne dépende pas de la bibliothèque Draw?
la source
visit()
méthode.La division que vous décrivez - en deux hiérarchies parallèles - est essentiellement le modèle de pont .
Vous craignez que cela rend l' abstraction raffinée (Rectangle, etc.) dépendante de l' implémentation (RectangleDrawer), mais je ne sais pas comment vous pourriez l'éviter complètement.
Vous pouvez certainement fournir une fabrique abstraite pour briser cette dépendance, mais vous avez toujours besoin d'un moyen de dire à la fabrique quelle sous-classe à créer, et cette sous-classe dépend toujours de l'implémentation affinée spécifique. Autrement dit, même si Rectangle ne dépend pas de RectangleDrawer, il a toujours besoin d'un moyen de dire à l'usine d'en créer un, et RectangleDrawer lui-même dépend toujours de Rectangle.
Il convient également de se demander s'il s'agit d'une abstraction utile. Le dessin d'un rectangle est-il si difficile qu'il vaut la peine de le mettre dans une classe différente, ou essayez-vous vraiment d'abstraire la bibliothèque graphique?
la source
RectangleDrawer
,CircleDrawer
etc. n'est peut-être pas le moyen le plus utile d'abstraire la bibliothèque graphique. Si, au lieu de cela, vous exposez un ensemble de primitives via une interface abstraite régulière, vous rompez toujours la dépendance.Jetez un œil à la sémantique des valeurs et au polymorphisme basé sur les concepts .
Ce travail a changé ma façon de voir le polymorphisme. Nous avons utilisé ce système avec beaucoup d'affect dans des situations répétées.
la source
La raison pour laquelle vous rencontrez un problème est que les objets ne doivent pas se dessiner. Dessiner quelque chose correctement dépend d'un milliard de pièces d'état et un rectangle ne comportera aucune de ces pièces. Vous devriez avoir un objet graphique central qui représente l'état de base comme backbuffer / depth buffer / shaders / etc, puis lui donner une méthode Draw ().
la source
Dog
ouCat
- l'objet chargé de les dessiner est beaucoup plus complexe que de dessiner un rectangle.