tags:

views:

113

answers:

4

I have a C# client and a java server. I have data object that go on the wire back and forth. Lets call them FooData.cs where everything is just a get and a set (no logic)

FooData data = new FooData();
data.Price = 10;
data.Quantity = 20;

i have other derived fields that i want to use in the application but dont need to be sent on the wire so i have anothe class

FooWrapper.cs.

I inject the data object into the wrapper

FooWrapper wrapper = new FooWrapper(Foodata);
wrapper.Price = 10;
wrapper.Quantity = 20;
double total  = wrapper.GetTotal();

and the wrapper has a lot of the same properties as the data object (and we just delegate down) or the wrapper also has a number of calculated properties. The only state the wrapper has is the data object (no other member variables)

We were having a debate about using this model versus using converters. The converter way would be to instead of having FooWrapper, have a FooBusinessObject and instead of injecting the "on the wire" object, we call a convert method that passes all of the data from the on the wire object to the business object.

FooData data = new FooData();
FooBusinessObject busObj = new FooBusinessObject();
busObj.Price = data.Price;
busObj.Quant= data.Quantity;
double total  = busObj.GetTotal();

Any thoughts on what is better (wrapper versus business object / converter)

+1  A: 

The way the question is written, the only real difference I can see is whether you pass the fooData instance in through the constructor or call a separate method that constructs it, but implicit in the first method is that the Wrapper object keeps a reference to the original object, whereas in the second approach it seems to me like you avoid this connection.

I think the underlying issue is really if you want to keep a reference to the original object. This may sometimes be relevant if the original object contains state that you will not be exposing to your application but could be necessary to perform updates.

If this is not the case then I would try to hide the wire-level objects away from your business logic. Part of the intention of wrapping is to protect your code from the details of the wire-level stuff, and the further up in the stack you let these things seep, the greater the chance they'll be used where not intended, increasing unintentional coupling.

krosenvold
+1  A: 

(edit) What version of C# are you using? With C# 3.0 you could place the "logic" bits (calculations etc) in extension methods in a busines logic assembly, but still see them via the DTO - i.e.

(data layer)

public class Foo {
    public int Bar {get;set;}
}

(business layer)

static class FooExt {
    public static int Blop(this Foo foo) {return 2 * foo.bar;}
}

(ui layer)

Foo foo = ...
int blop = foo.Blop();


What model are you using to transfer the data? web services? xml? data-contracts? binary? Most would allow you to ignore the extra properties without any extra code (i.e. no need for a wrapper/facade object):

XmlSerializer:

[Serializable]
public class MyData {
    public int Foo {get;set;} // is sent
    [XmlIgnore]
    public int Bar {get {...} set {...}} // is ignored
}

DataContractSerializer:

[DataContract]
class MyData {
    [DataMember]
    public int Foo {get;set;} // is sent
    public int Bar {get {...} set {...}} // is ignored
}

If you are talking binary, there are portable java/C#-friendly models such as "protocol buffers" - Jon Skeet has a C# port of the official java version (allowing you to use very similar code on both sides) - or I have a more C#-idiomatic version (protobuf-net):

ProtoSerializer:

[ProtoContract]
class MyData {
    [ProtoMember(1)]
    public int Foo {get;set;} // is sent
    public int Bar {get {...} set {...}} // is ignored
}
Marc Gravell
A: 

Rather than thinking in terms of objects that go back and forth, could you think instead of the business events that one side needs to notify the other and the minimum amount of data required to describe each one?

asplake
A: 

I'd tend to use the wire object to build the other one, and not wrap it. "How the data is transferred" and "how the object is stored in memory" are two different concerns, and not mixing them is a generally good idea. At some point, you may use a different 'wire' technology not compatible with your existing wire objects, and if that happens, I'd rather modify a converter class than my core business logic.

This also gives you the flexibility to modify your wire objects to contain more/less/different data without having to impact your core business functionality. An all-around win, in my book.

kyoryu