Бизнес-объекты должны смочь создать свой собственный DTOs?

Предположим, что у меня есть следующий класс:

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

... и DTO для переноса информации о камере через сервисную границу (WCF), скажем, для просмотра в 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 был передан в том, чтобы Камера выставила свои данные. Это удаляет зависимость от уровня Contracts (Камера больше не должна знать о CameraData):

class Camera
{
    // beep beep I'm a jeep

    public void ExposeToReporter(IReporter reporter)
    {
        reporter.GetCameraInfo(exposure, brightness, contrast, regionOfInterest);
    }
}

Таким образом, который я должен сделать? Я предпочитаю второе, но это требует, чтобы IReporter имел поле CameraData (который изменяется GetCameraInfo()), который чувствует себя странным. Кроме того, если существует какое-либо еще лучшее решение, совместно используйте со мной! Я - все еще объектно-ориентированный newb.

5
задан xofz 5 April 2010 в 22:11
поделиться

5 ответов

Я бы обычно сказал нет , они не должны, потому что 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 ). У вас есть практически вся простота использования вашей исходной версии, но без привязки.

Если вы создаете эти зависимости, потому что пытаетесь создать объект CameraData из частных данных Camera , которые не публикуются публично, то моя немедленная реакция будет такой: не совсем верно об этом дизайне.Почему бы не сделать доступными только для чтения свойства объекта Camera ? Если вы все равно предоставляете доступ к ним внешнему миру с помощью метода ToData , то вы явно не скрываете эту информацию, вы просто затрудняете доступ к ней.

Что, если через 3 месяца вы решите, что вам нужен другой тип DTO? Вам не нужно изменять объект Camera , ориентированный на домен, каждый раз, когда вы хотите поддержать новый вариант использования. На мой взгляд, лучше поместить в класс несколько общедоступных свойств, доступных только для чтения, чтобы картографы могли получить доступ к нужным им атрибутам.

13
ответ дан 18 December 2019 в 09:48
поделиться

Первый (разоблачение DTO) для меня намного предпочтительнее. Это проще, будет работать быстрее, будет проще в понимании и обслуживании. Поскольку DTO действительно не зависит от объекта базы данных, он по-прежнему легко достигает цели уменьшения зависимостей.

0
ответ дан 18 December 2019 в 09:48
поделиться

Я помещаю методы to / from в свои DTO:

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

    public static CameraData FromCamera(Camera c) { ... }
}

Таким образом, мои объекты домена не должны знать о моих DTO.

0
ответ дан 18 December 2019 в 09:48
поделиться

Обычно я делаю это следующим образом: бизнес-объекты «чисты» в DLL (библиотеках) бизнес-уровня. Затем я добавляю метод расширения Camera.MapToCameraDataContract в слой WCF. У меня также обычно есть метод обратного расширения (CameraDataContract.MapToCamera) на уровне обслуживания.

По сути, я делаю это первым способом, но метод ToData - это метод расширения, о котором знает только уровень WCF.

4
ответ дан 18 December 2019 в 09:48
поделиться

Являются ли ваши службы WCF WCF?

Если да, то вы можете использовать свои бизнес-объекты в качестве DTO (пока ваши бизнес-объекты игнорируют постоянство). Если вы это сделали, я бы рекомендовал изменить ваш класс CameraData на интерфейс ICameraData и заставить Camera реализовать ICameraData. Сохраните атрибуты (DataContract и т. Д.) В интерфейсе.

Затем вы можете передать бизнес-объект от клиента к серверу. Помните о любой логике, относящейся конкретно к клиентской или серверной стороне.

Первое изображение в моем сообщении в блоге здесь показывает, насколько легко повторно использовать ваши бизнес-объекты на стороне клиента (диалоговое окно - это то, что отображается, когда вы делаете «добавление ссылки на службу»). В сообщении блога есть информация об одной из ловушек повторного использования бизнес-объектов.

Я не могу сказать, чего вы пытаетесь достичь с помощью ExposeToReporter, но вы правы, это выглядит неправильно, лично я бы поместил метод в IReporter, который принимает параметр ICameraData, а затем установил детали для репортера. внутри этого.

Замечательный источник изучения этого материала - dnrtv . Смотрите все с WCF в названии, но особенно Extreme WCF от Мигеля Кастро!

0
ответ дан 18 December 2019 в 09:48
поделиться
Другие вопросы по тегам:

Похожие вопросы: