Digamos que eu tenho uma hierarquia de Item
classes: Rectangle, Circle, Triangle
. Quero poder desenhá-los, então minha primeira possibilidade é adicionar um Draw()
método virtual a cada um:
class Item {
public:
virtual ~Item();
virtual void Draw() =0;
};
No entanto, desejo dividir a funcionalidade de desenho em uma biblioteca Draw separada, enquanto a biblioteca Core contém apenas as representações básicas. Há algumas possibilidades em que posso pensar:
1 - A DrawManager
que pega uma lista de se Item
precisa usar dynamic_cast<>
para descobrir o que fazer:
class DrawManager {
void draw(ItemList& items) {
FOREACH(Item* item, items) {
if (dynamic_cast<Rectangle*>(item)) {
drawRectangle();
} else if (dynamic_cast<Circle*>(item)) {
drawCircle();
} ....
}
}
};
Isso não é ideal, pois depende do RTTI e força uma classe a estar ciente de todos os itens na hierarquia.
2 - A outra abordagem é adiar a atribuição de responsabilidades a uma ItemDrawer
hierarquia ( RectangleDrawer
, etc):
class Item {
virtual Drawer* GetDrawer() =0;
}
class Rectangle : public Item {
public:
virtual Drawer* GetDrawer() {return new RectangleDrawer(this); }
}
Isso alcança a separação de preocupações entre a representação básica dos itens e o código para o desenho. O problema, porém, é que as classes de itens dependem das classes de desenho.
Como posso separar esse código de desenho em uma biblioteca separada? A solução para os Itens retornar uma classe de fábrica com alguma descrição? No entanto, como isso pode ser definido para que a biblioteca Core não dependa da biblioteca Draw?
fonte
visit()
método.A divisão que você descreve - em duas hierarquias paralelas - é essencialmente o padrão da ponte .
Você se preocupa que isso torne a abstração refinada (Rectangle etc.) dependente da implementação (RectangleDrawer), mas não tenho certeza de como você poderia evitar isso completamente.
Você certamente pode fornecer uma fábrica abstrata para quebrar essa dependência, mas ainda precisa de alguma maneira de dizer à fábrica qual subclasse criar e essa subclasse ainda depende da implementação refinada específica. Ou seja, mesmo que o Rectangle não dependa do RectangleDrawer, ele ainda precisará de uma maneira de instruir a fábrica a criar um, e o próprio RectangleDrawer ainda depende do Rectangle.
Também vale a pena perguntar se isso é uma abstração útil. Desenhar um retângulo é tão difícil que vale a pena colocar em uma classe diferente ou você está realmente tentando abstrair a biblioteca de gráficos?
fonte
RectangleDrawer
,CircleDrawer
etc. pode não ser a forma mais útil para abstrair a biblioteca de gráficos. Se, em vez disso, você expor um conjunto de primitivas por meio de uma interface abstrata regular, você ainda interrompe a dependência.Veja o valor da semântica e do polimorfismo baseado em conceitos .
Este trabalho mudou a maneira como encaro o polimorfismo. Usamos esse sistema com grande efeito em situações repetidas.
fonte
A razão pela qual você está tendo um problema é porque os objetos não devem se desenhar. Desenhar algo corretamente depende de um bilhão de peças de estado e um retângulo não terá nenhuma dessas peças. Você deve ter um objeto gráfico central que represente o estado central como backbuffer / depth buffer / shaders / etc e, em seguida, forneça um método Draw ().
fonte
Dog
ouCat
- o objeto responsável por desenhá-las é muito mais complexo do que desenhar um retângulo.