Reputation: 39753
I have the following datastructure consisting of a table and a list of attributes (simplified):
class Table {
List<Attribute> m_attributes;
}
abstract class Attribute {}
class LongAttribute extends Attribute {}
class StringAttribute extends Attribute {}
class DateAttribute extends Attribute {}
...
Now I want to do different actions with this datastructure:
My first attempt was to put all these functionality inside the Attribute
, but then the Attribute
was overloaded with very different responsibilities.
It feels like a visitor pattern could do the job very well instead, but on the other side it looks like overkill for this simple structure.
What's the most elegant way to solve this?
Upvotes: 0
Views: 296
Reputation: 39753
In the end, I used the visitor pattern. Now looking back, it was a good choice.
Upvotes: 0
Reputation: 8004
I dunno why you'd store stuff in a database yourself these days instead of just using hibernate, but here's my call:
LongAttribute
, DateAttribute
, StringAttribute
,… all have different internals (i.e. fields specific to them not present in Attribute class), so you cannot create one generic method to serialize them all. Now XML, SQL and plain text all have different properties when serializing to them. There's really no way you can avoid writing O(#subclasses of Attribute
#output formats)* different methods of serializing.
Visitor is not a bad pattern for serializing. True, it's a bit overkill if used on non-recursive structures, but a random programmer reading your code will immediately grasp what it is doing.
Now for deserialization (from XML to object, from SQL to object) you need a Factory.
One more hint, for SQL update you probably want to have something that takes old version of the object, new version of the object and creates update query only on the difference between them.
Upvotes: 1
Reputation: 67820
The Command pattern comes to mind, or a small variation of it.
You have a bunch of classes, each of which is specialized to do a certain thing with your data class. You can keep these classes in a hashmap or some other structure where an external choice can pick one for execution. To do your thing, you call the selected Command's execute() method with your data as an argument.
Edit: Elaboration.
At the bottom level, you need to do something with each attribute of a data row. This indeed sounds like a case for the Visitor pattern: Visitor simulates a double dispatch operation, insofar as you are able to combine a variable "victim" object with a variable "operation" encapsulated in a method.
Your attributes all want to be xml-ed, text-ed, insert-ed updat-ed and initializ-ed. So you end up with a matrix of 5 x 3 classes to do each of these 5 operations to each of 3 attribute types. The rest of the machinery of the visitor pattern will traverse your list of attributes for you and apply the correct visitor for the operation you chose in the right way for each attribute.
Writing 15 classes plus interface(s) does sound a little heavy. You can do this and have a very general and flexible solution. On the other hand, in the time you've spent thinking about a solution, you could have hacked together the code to it for the currently known structure and crossed your fingers that the shape of your classes won't change too much too often.
Where I thought of the command pattern was for choosing among a variety of similar operations. If the operation to be performed came in as a String, perhaps in a script or configuration file or such, you could then have a mapping from
"xml" -> XmlifierCommand
"text" -> TextPrinterCommand
"serial" -> SerializerCommand
...where each of those Commands would then fire up the appropriate Visitor to do the job. But as the operation is more likely to be determined in code, you probably don't need this.
Upvotes: 1
Reputation: 15783
I would look at using a combination of JAXB and Hibernate.
JAXB will let you marshall and unmarshall from XML. By default, properties are converted to elements with the same name as the property, but that can be controlled via @XmlElement and @XmlAttribute annotations.
Hibernate (or JPA) are the standard ways of moving data objects to and from a database.
Upvotes: 1