views:

136

answers:

2

When an object has various formats (XML,CSV) it can be represented in, where should one store knowledge of those formats.

Should the object have knowledge of how it's represented in XML (i.e. letting the object convert itself through some method on the object such as GetXML()). Is this too much knowledge for the object and should this be stored externally in a repository/service/other layer?

If it is stored in a repository, what happens in the use case where the XML representation of the object must be persisted to a database along with other information, e.g.:-

insert into order values(1, '2004', <order><amount>2</amount><price>19.99</price></order>);

...the knowledge of the object's XML structure would be in the XML repository, however the SQL repository would also need this knowledge, and this seems like duplication.

I am unsure as to whether the service layer should be holding object representations either, as it does not seem like this is business logic.

What is the recommended implementation for this use case?

+3  A: 

Generally speaking you want the object's XML (or other...) formatting code to be separate for the object itself. The practical reason for this is wanting to have more than one XML representation (say a summary and detailed representation). If these methods where all part of the object's API then you start having:

public String GetShortXml(){ ... }
public String GetFullXml(){ ... }
public String GetCsv(){ ... }
public String GetJson(){ ... }

As part of the API of every single business object and that gets ugly fast. Furthermore this violates the single responsibility priciple as each class is responsible for both what id does and representing itself as XML, JSON, CSV, etc.

Thus, it is often best to have a class that knows how to format the business objects you care about and have a SummaryXmlFormatter, DetailedXmlFormatter, CsvFormatter, JsonFormater, etc.

You can go one step further and have your objects implement an IFormattable interface (the following is an adaptation of the visitor patter which gives us double dispatch goodness):

public interface IFormattable {
    public String Format(IFormatter formatter);
}

with implementations like:

public String Format(IFormatter formatter){
    return formatter.FormatBusinessObjectOne(this);
}

with the IFormatter interface defined thusly:

public interface IFormatter{
    public String FormatBuisinessObjectOne(BusinessObjectOne boo);
    public String FormatBuisinessObjectTwo(BusinessObjectTwo bot);
    ...
}

Which would allow your formatting calls to be dispatched polymorphically. Depending on your requirements may or may not be useful (do you ever hold a collection of different types and thus require polymorphic dispatch or is overloading enough?).

Your calls to format would then look like:

IFormatter formatter = new XmlFormatter();
BusinessObjectOne boo = new BusinessObjectOne(...);

// With visitor like double dispatch
String xml = boo.Format(formatter);

// Without 
String xml = formatter.FormatBusinessObjectOne(boo);

// With overloading
String xml = formatter.Format(boo);
Aaron Maenpaa
Really nice techniques in this answer, thanks for taking the time.
rodbv
A: 

What is it that you want to store in the DB?

insert into order 
values(1, '2004', '<order><amount>2</amount><price>19.99</price></order>');

or

insert into order values(1, '2004', 2, 19.99);

?

tuinstoel
The first one:insert into order values(1, '2004', '<order><amount>2</amount><price>19.99</price></order>');
Laz