代码之家  ›  专栏  ›  技术社区  ›  xofz

业务对象是否应该能够创建自己的DTO?

  •  5
  • xofz  · 技术社区  · 16 年前

    假设我有以下课程:

    class Camera
    {
        public Camera(
            double exposure,
            double brightness,
            double contrast,
            RegionOfInterest regionOfInterest)
        {
            this.exposure = exposure;
            this.brightness = brightness;
            this.contrast = contrast;
            this.regionOfInterest = regionOfInterest;
        }
    
        public void ConfigureAcquisitionFifo(IAcquisitionFifo acquisitionFifo)
        {
            // do stuff to the acquisition FIFO
        }
    
        readonly double exposure;
        readonly double brightness;
        readonly double contrast;
        readonly RegionOfInterest regionOfInterest;
    }
    

    …以及一个用于跨服务边界(wcf)传输摄像机信息的DTO,例如,用于在winforms/wpf/web应用程序中查看:

    using System.Runtime.Serialization;
    
    [DataContract]
    public class CameraData
    {
        [DataMember]
        public double Exposure { get; set; }
    
        [DataMember]
        public double Brightness { get; set; }
    
        [DataMember]
        public double Contrast { get; set; }
    
        [DataMember]
        public RegionOfInterestData RegionOfInterest { get; set; }
    }
    

    现在我可以添加一个方法 Camera 要公开其数据:

    class Camera
    {
        // blah blah
    
        public CameraData ToData()
        {
            var regionOfInterestData = regionOfInterest.ToData();
    
            return new CameraData()
            {
                Exposure = exposure,
                Brightness = brightness,
                Contrast = contrast,
                RegionOfInterest = regionOfInterestData
            };
        }
    }
    

    ,我可以创建一个方法,该方法要求传入一个特殊的IReporter,以便照相机将其数据暴露给。这消除了对合同层的依赖性(相机不再需要了解cameradata):

    class Camera
    {
        // beep beep I'm a jeep
    
        public void ExposeToReporter(IReporter reporter)
        {
            reporter.GetCameraInfo(exposure, brightness, contrast, regionOfInterest);
        }
    }
    

    那我该怎么办?我喜欢第二个,但它要求iReport有一个cameradata字段 GetCameraInfo() 这感觉很奇怪。另外,如果还有更好的解决方案,请与我分享!我还是一个面向对象的新手。

    5 回复  |  直到 16 年前
        1
  •  13
  •   Aaronaught    16 年前

    我一般会说 它们不应该,因为DTO是特定于服务或应用程序的,而域模型是您的“最内层”层,不应该有依赖性。DTO是一个实现细节 其他 而不是领域模型,因此,它打破了领域模型了解它们的抽象。

    你考虑过看吗 AutoMapper 为了这个?你这样写的代码会少得多。在这种情况下,我认为你可以简单地摆脱:

    Mapper.CreateMap<RegionOfInterest, RegionOfInterestData>();
    Mapper.CreateMap<Camera, CameraData>();
    

    稍后:

    CameraData cd = Mapper.Map<Camera, CameraData>(camera);
    

    这不仅减少了代码搅乱,而且将映射代码划分为自己的“映射层”——您有一个或多个模块来注册这些映射,您可以将这些映射放入真正使用DTO的任何程序集中。

    当然,您可以始终创建扩展方法来简化实际映射:

    public static class CameraExtensions
    {
        public static CameraData ToCameraData(this Camera camera)
        {
            return Mapper.Map<Camera, CameraData>(camera);
        }
    }
    

    这使得整件事像写作一样简单 camera.ToCameraData() 但是 没有 在域对象之间创建硬依赖项( Camera )和DTO( CameraData )您基本上拥有原始版本的所有易用性,但是没有耦合。

    如果您正在创建这些依赖项,因为您正在尝试创建 喀麦拉达 来自private的对象 照相机 如果数据没有公开,那么我的直接反应是,这种设计有点不对。为什么不在上公开只读属性 照相机 对象?不管怎样,如果你要让外界通过 ToData 方法,那么显然你没有隐藏这些信息,你只是让它变得更麻烦。

    如果你决定三个月后你需要一种不同的DTO呢?您不应该修改以域为中心的 照相机 每当您想要支持一个新的用例时,对象。在我看来,最好在类中放置一些只读公共属性,以便映射器能够访问所需的属性。

        2
  •  4
  •   Daniel Auger    16 年前

    我通常这样做:业务对象在业务层DLL中是“纯”的。然后在wcf层中添加camera.maptocameradatacontract扩展方法。我还典型地在服务层上有反向扩展方法(cameradatacontract.maptocamera)。

    所以本质上,我是第一种方法,但是todata方法是一种扩展方法,只有wcf层知道。

        3
  •  0
  •   Jay    16 年前

    第一个(暴露DTO)比我好得多。它更简单,运行速度更快,更容易理解和维护。由于DTO确实不依赖于数据库对象,因此它仍然很容易实现减少依赖性的目标。

        4
  •  0
  •   Gabe Moothart    16 年前

    我把to/from方法放在DTO上:

    [DataContract]
    public class CameraData
    {
        ...
        public Camera ToCamera() { ... }
    
        public static CameraData FromCamera(Camera c) { ... }
    }
    

    这样我的域对象就不必知道我的DTO了。

        5
  •  0
  •   wallismark    16 年前

    您的服务是WCF到WCF吗?

    如果是,那么您可以选择将业务对象用作DTO(只要您的业务对象没有持久性)。如果您这样做了,我建议您将cameradata类更改为icameradata接口,并使cameradata实现icameradata。保留接口上的属性(DataContract等)。

    然后您可以将业务对象从客户机传递到服务器。注意任何特定于客户机或服务器端的逻辑。

    我的第一张照片 blog post 这里显示了重新使用Business Objects对象客户端的容易程度(对话框是在执行“添加服务引用”时显示的对话框)。博客上有一些关于重新使用biz对象的信息。

    我不知道你想用ExposeToReporter实现什么,但是你是对的,它看起来不正确,我个人会在iReporter上放置一个方法,它采用一个iMeradata参数,然后在其中设置Reporter的详细信息。

    学习这些东西的一个很好的来源是 dnrtv . 观看所有与世界自然基金会在标题,但特别是极端世界自然基金会米盖尔卡斯特罗!