Should business objects create their own DTOs?

Suppose I have the following class:

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; } 

... and DTO for transmitting camera information along the service boundary (WCF), say, for viewing in the WinForms / WPF / Web application:

 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; } } 

Now I can add a Camera method to expose its data:

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

or, I can create a method that requires a special IReporter to be passed for the camera to open its data. This eliminates the dependency on the Contract level (the camera no longer needs to know about CameraData):

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

So what should I do? I prefer the latter, but the IReporter requires a CameraData field (which changes to GetCameraInfo() ), which seems strange. Also, if there is an even better solution, please share with me! I'm still an object oriented newb.

+4
source share
5 answers

I would say no, they should not, because DTOs are service or application specific, while the domain model is your “innermost” layer and should not have any dependencies. DTOs are part of the implementation of something other than a domain model, and therefore it violates the abstraction for your domain model to know about them.

Have you considered AutoMapper for this? You will end up writing a lot less code. In this case, I think you can just off:

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

And later:

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

This not only reduces code failure, but also comparts the display code in its own “display layer”. You have one or more modules that register these mappings, which you can add, depending on which assembly really uses the DTO.

And of course, you can always create extension methods to simplify the actual display:

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

It makes everything as simple as writing camera.ToCameraData() , but without , creating a tight relationship between the domain object ( Camera ) and DTO ( CameraData ). You basically have all the ease of use of the original version, but without communication.

If you create these dependencies because you are trying to create a CameraData object from private Camera data that is not publicly disclosed, then my immediate reaction will be, something not quite right in this design. Why not open read-only properties on the Camera object? If you still provide the outside world with access to them using the ToData method, then you obviously do not hide this information, you just make it more cumbersome to get.

What if you decide 3 months on the road that you need a different type of DTO? You do not need to change the object oriented to the Camera domain every time you want to support a new use case. It’s better, in my opinion, to add some read-only public properties to the class so that recipients can access the attributes they need.

+12
source

I usually talk about it this way: business objects are "clean" in a business-level DLL. Then I add the extension method Camera.MapToCameraDataContract in the WCF layer. I also have a backward extension method (CameraDataContract.MapToCamera) at the service level.

So, essentially, I do it the first way, but the ToData method is an extension method that only the WCF layer knows about.

+3
source

The first (exposing the DTO) is much preferable for me. It is simpler, faster, easier to understand and maintain. Since the DTO does not really have a dependency on a database object, it still easily achieves the goal of reducing dependencies.

0
source

I put to / methods on my DTOs:

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

Therefore, my domain objects should not know about my DTOs.

0
source

Are your WCF services for WCF?

If so, you can use your business objects as a DTO (as long as your business objects are not stored at an unfamiliar level). If you do, I recommend changing the CameraData class to the ICameraData interface and making Camera ICameraData. Store attributes (DataContract, etc.) in the interface.

You can then transfer the business object from the client to the server. Keep in mind any logic that is specifically client or server.

The first image in my blog post shows how easy it is to reuse client-side objects of business objects (the dialog box is what is shown when you add the link to the service "). The blog post contains some information about one of the attempts to reuse objects biz.

I can’t say what you are trying to achieve with ExposeToReporter, but you are right, it doesn’t look right, I personally would put a method on IReporter that takes the ICameraData parameter and then sets the reporter details inside it.

An amazing source of training for this material is dnrtv . See everything with WCF in the title, but especially Extreme WCF from Miguel Castro!

0
source

Source: https://habr.com/ru/post/1306063/


All Articles