在核心数据模型上公开您的核心

时间:2009-02-08 12:52:46

标签: c# model

我有一个C#客户端和一个java服务器。我的数据对象来回传输。让我们称之为FooData.cs,其中一切都只是一个get和一个集合(没有逻辑)

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

我有其他派生字段,我想在应用程序中使用,但不需要在线上发送,所以我有另一个类

FooWrapper.cs。

我将数据对象注入包装器

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

并且包装器具有许多与数据对象相同的属性(我们只是委托下来),或者包装器也有许多计算属性。包装器唯一的状态是数据对象(没有其他成员变量)

我们正在讨论使用此模型与使用转换器。转换方式不是使用FooWrapper,而是使用FooBusinessObject,而不是注入“on the wire”对象,我们调用一个convert方法,将所有数据从wire对象传递给业务对象。

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

关于什么是更好的想法(包装器与业务对象/转换器)

4 个答案:

答案 0 :(得分:1)

问题的写法,我能看到的唯一真正的区别是你是通过构造函数传递fooData实例还是调用构造它的单独方法,但第一种方法隐含的是Wrapper对象保持一个引用原始对象,而在第二种方法中,在我看来,你似乎避免了这种联系。

我认为如果你想保留对原始对象的引用,那么根本问题就在于此。如果原始对象包含您不会向您的应用程序公开的状态,但可能是执行更新所必需的,那么可能有时是相关的。

如果不是这种情况,那么我会尝试将线级对象隐藏在业务逻辑之外。包装意图的一部分是保护你的代码免受线级事物的细节的影响,并且你让这些东西渗透到堆栈中的进一步,它们在不需要的地方被使用的可能性越大,增加了无意的耦合

答案 1 :(得分:1)

(编辑)您使用的是什么版本的C#?使用C#3.0,你可以将“逻辑”位(计算等)放在商业逻辑组件中的扩展方法中,但仍然可以通过DTO看到它们 - 即。

(数据层)

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

(业务层)

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

(ui layer)

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

您使用什么型号来传输数据?网页服务? XML?数据合同?二进制?大多数允许您忽略额外的属性而不需要任何额外的代码(即不需要包装器/外观对象):

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
}

如果您正在谈论二进制文件,那么有便携式java / C#友好模型,例如“protocol buffers” - Jon Skeet有一个C# port官方java版本(允许您使用非常相似的代码)两边) - 或者我有一个更多的C#-idiomatic版本(protobuf-net):

ProtoSerializer

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

答案 2 :(得分:0)

您是否可以考虑一方需要通知另一方的业务事件以及描述每一方所需的最少数据量,而不是根据反复出现的对象进行思考?

答案 3 :(得分:0)

我倾向于使用wire对象构建另一个,而不是包装它。 “如何传输数据”和“对象如何存储在存储器中”是两个不同的问题,而不是混合它们通常是个好主意。在某些时候,您可能会使用与现有线对象不兼容的不同“线”技术,如果发生这种情况,我宁愿修改转换器类而不是我的核心业务逻辑。

这使您可以灵活地修改线对象以包含更多/更少/不同的数据,而不必影响您的核心业务功能。在我的书中全面取胜。