views:

30

answers:

2

I tend to have a class to describe a general concept and subclasses to describe variances in that concept. For example, Polygon <|-- {Rectangle, Triangle, etc.}.

However, I often find I have various representations of these hierarchies. For example, I want to keep the graphical representation (eg, a QPolygon), or the physical representation (mass, centerOfMass), etc. separate from another representation I have.

In my case, I have a hierarchy of purely-data objects (Command <|-- {WaitCommand, UnknownCommand, etc.}) and I have a matching GUI representation for each of the data classes (WaitCommandPanel, UnknownCommandPanel).

My problem is that once I construct the data representation I need to make the leap from the data to the GUI.

Given a list of data objects, I want to be able to construct the corresponding GUI elements but keep the two representations separate.

One [lousy] solution would be for each Command to have the ability (ie, Command::getPanel()) to return its GUI representation. I don't like this because my data classes now have representation code in them.

The other solution (which I've adopted for the time being) is to do a lookup. That is, when initiating the GUI, given a list of Commands (the generalization), the function determines what object to create based on its specialized type. I don't like this either.

Any suggestions?

A: 

IMHO, neither data class no rendering class have a responsibility to make a decision about which renderer to use for a given data object. I do prefer your second option. I usually use a map that maps data-type into a renderer class. Also note that such mapping is context specific (web rendering will use different renderers from destop app, or fitness context).

Such mapping can be constructed automatically, for example using attributes (in .Net) or maybe naming convention (in Lua). Or using external XML-config file.

Summary: somebody have to make that decision, and according to SRP neither renderer nor data object shall be responsible for that. Such logic is application-context specific, and as such should be 'above' both of those actors (i.e. renderer and data).

I've Matryoshka-dolled my GUI (main window has project panels, project panels have command panels, etc.) Each level isn't aware of where it is nested/the level above. However, each level does know about the levels below (that's the context in which the lower levels exist) I suppose I'll leave it to the level in which the panels are used to decide. I don't need any fancy XML as the pairing of the classes does not change (`X` will always use `XPanel` as a GUI representation.) Also, this is easy enough to associate in python using dictionaries: type(X) => constructor for XPanel. Thanks.
jkiv
especially with Python, you could use a naming convention to do the association. Traverse the scope and populate your renderer lookup map, such that any class of form (?<obj>.*)Renderer be registered as: type(obj) => type(objRenderer). So that you will just need to define classes MyData and MyDataRenderer - and they will automatically get associated. (IMHO this approach is **cool**, but not practical - will cause more problems than it solves)
A: 

You may want to look into using an inversion of control (IoC) container to build up your classes.

Each class would contain an interface of of it's associated class. The IoC container would then inject the implementation of that class into your object according how you have configured it.

Mongus Pong
I'll look into it, thanks!
jkiv