Digamos que tengo una jerarquía de Item
clases: Rectangle, Circle, Triangle
. Quiero poder dibujarlos, así que mi primera posibilidad es agregar un Draw()
método virtual a cada uno:
class Item {
public:
virtual ~Item();
virtual void Draw() =0;
};
Sin embargo, quiero dividir la funcionalidad de dibujo en una biblioteca Draw separada, mientras que la biblioteca Core contiene solo las representaciones básicas. Hay un par de posibilidades en las que puedo pensar:
1 - A DrawManager
que toma una lista de Item
sy tiene que usar dynamic_cast<>
para determinar qué hacer:
class DrawManager {
void draw(ItemList& items) {
FOREACH(Item* item, items) {
if (dynamic_cast<Rectangle*>(item)) {
drawRectangle();
} else if (dynamic_cast<Circle*>(item)) {
drawCircle();
} ....
}
}
};
Esto no es ideal, ya que se basa en RTTI y obliga a una clase a conocer todos los elementos de la jerarquía.
2 - El otro enfoque es diferir la responsabilidad del dibujo a una ItemDrawer
jerarquía ( RectangleDrawer
, etc.):
class Item {
virtual Drawer* GetDrawer() =0;
}
class Rectangle : public Item {
public:
virtual Drawer* GetDrawer() {return new RectangleDrawer(this); }
}
Esto logra la separación de preocupaciones entre la representación base de los Artículos y el código para dibujar. Sin embargo, el problema es que las clases de ítems dependen de las clases de dibujo.
¿Cómo puedo separar este código de dibujo en una biblioteca separada? ¿Es la solución para que los artículos devuelvan una clase de fábrica de alguna descripción? Sin embargo, ¿cómo se puede definir esto para que la biblioteca Core no dependa de la biblioteca Draw?
fuente
visit()
método.La división que describe, en dos jerarquías paralelas, es esencialmente el patrón del puente .
Le preocupa que haga que la abstracción refinada (Rectángulo, etc.) dependa de la implementación (RectangleDrawer), pero no estoy seguro de cómo podría evitarlo por completo.
Ciertamente, puede proporcionar una fábrica abstracta para romper esa dependencia, pero aún necesita alguna forma de decirle a la fábrica qué subclase crear, y esa subclase aún depende de la implementación refinada específica. Es decir, incluso si Rectangle no depende de RectangleDrawer, todavía necesita una forma de decirle a la fábrica que construya uno, y RectangleDrawer sí mismo depende de Rectangle.
También vale la pena preguntar si esta es una abstracción útil. ¿Dibujar un rectángulo es tan difícil que vale la pena ponerlo en una clase diferente, o realmente estás tratando de abstraer la biblioteca de gráficos?
fuente
RectangleDrawer
,CircleDrawer
etc. , puede no ser la forma más útil de abstraer la biblioteca de gráficos. Si, en cambio, expone un conjunto de primitivas a través de una interfaz abstracta regular, aún así rompe la dependencia.Eche un vistazo a la semántica de valores y al polimorfismo basado en conceptos .
Este trabajo ha cambiado mi forma de ver el polimorfismo. Hemos utilizado este sistema con gran efecto en situaciones repetidas.
fuente
La razón por la que tiene un problema es porque los objetos no deben dibujarse solos. Dibujar algo correctamente depende de mil millones de piezas de estado y un Rectángulo no tendrá ninguna de esas piezas. Debe tener un objeto gráfico central que represente el estado del núcleo, como backbuffer / profundidad buffer / shaders / etc, y luego darle un método Draw ().
fuente
Dog
oCat
: el objeto responsable de dibujarlas es mucho más complejo que dibujar un rectángulo.