While designing the class that manages my game objects the other night on a project I came across an interesting pattern. Using the visitor pattern with a mediator to add objects.
interface IRenderable {
public void DrawMe();
}
class Renderer {
public void Add(IRenderable renderable);
public void Remove(IRenderable renderable);
}
This is normal looking code for most applications. The power of being able to add random things that can be drawn is very useful. There are several problems with this first it can be important what order things are rendered when drawing 2d and 3d graphics. Also for the purposes of batching it may be very important to group like objects together.
These two problems can make things somewhat messy. Its possible to overcome them naturally. For instance we could include an integer that describes the order which renderables are to be drawn and sort them that way. For batching each renderable could queue it self up for rendering and then after a certain number of objects are in the queue or if it needs to be flushed for example if we are done rendering. Of course the batcher would have to somehow register it self with the renderer also since presumably only the renderer knows when its done drawing and any retained style buffers need to be flushed.
There is a simpler way which at first may seem silly and that is to have the objects register themselves at the request of the renderer--basically the visitor pattern.
interface IRenderable {
public void DrawMe();
public void Add(Renderer renderer);
public void Remove(Renderer renderer);
}
class Renderer {
public void AddSpecialDohicky(Dohicky dohicky);
public void RemoveSpecialDohicky(Dohicky dohicky);
public void Add(IRenderable renderable) {
renderable.Add(this);
}
public void Remove(IRenderable renderable) {
renderable.Remove(this);
}
}
This allows for all sorts of interesting behavior. Also IRenderable could still support a basic one size fits all DrawMe() call if needed. Another side effect of this is that the Dohickys don't have to actually to be implementers of IRenderable which leaves things wide open for using composition instead of inheritance.
Naturally the draw back is that the Renderer is coupled with Dohickies but it makes it much easier to add optimizations to your renderer since it for example can cross coordinate with other objects being rendered so you do not have a bunch of objects operating in a vacuum simply for the sake of proper OO design. Like everything its all a matter of trade offs.
0 comments:
Post a Comment