هل يجب أن تكون كائنات العمل قادرة على إنشاء DTOs الخاصة بها؟

StackOverflow https://stackoverflow.com/questions/2581490

  •  24-09-2019
  •  | 
  •  

سؤال

افترض أن لدي الفصل التالي:

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 خاص للكاميرا لفضح بياناتها. هذا يزيل الاعتماد على طبقة العقود (لم تعد الكاميرا يجب أن تعرف عن المصور):

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

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

إذن ما الذي يجب أن أفعله؟ أنا أفضل الثانية ، لكنه يتطلب من iReporter أن يكون لديه حقل مصور (يتم تغييره GetCameraInfo()) ، والتي تشعر غريب. أيضًا ، إذا كان هناك حل أفضل ، فيرجى مشاركتي معي! ما زلت نيوب موجه نحو الكائن.

هل كانت مفيدة؟

المحلول

سأقول عموما رقم, ، لا ينبغي عليهم ذلك ، لأن DTOs خاصة بالخدمة أو التطبيق ، في حين أن نموذج المجال هو طبقة "الأعمق" ولا ينبغي أن يكون لها أي تبعيات. DTOs هي تفاصيل تنفيذ لشيء ما آخر من نموذج المجال ، وبالتالي ، فإنه يكسر التجريد لنموذج المجال الخاص بك لمعرفة عنهم.

هل فكرت في النظر في السيارات لهذا؟ سينتهي بك الأمر إلى كتابة رمز أقل بكثير بهذه الطريقة. في هذه الحالة ، أعتقد أنك ستكون قادرًا على الابتعاد ببساطة:

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

وبعد ذلك:

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

هذا لا يقلل فقط من المزيج من الكود ، بل يزداد تقسيم رمز التعيين في "طبقة التعيين" الخاصة به - لديك وحدات أو عدة وحدات تسجل هذه التعيينات التي يمكنك وضعها في أي مجموعة تستخدم DTOs بالفعل.

وبالطبع يمكنك دائمًا إنشاء طرق تمديد لتبسيط الخرائط الفعلية:

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 الكائن في كل مرة تريد دعم حالة الاستخدام الجديدة. من الأفضل ، في رأيي ، وضع بعض الخصائص العامة للقراءة فقط في الفصل حتى يتمكن التعدادات من الوصول إلى السمات التي يحتاجونها.

نصائح أخرى

عادةً ما أقوم بذلك على هذا النحو: كائنات العمل "نقية" في طبقة العمل DLL (S). أقوم بعد ذلك بإضافة Camera.MaptocamerAdataContrict Method في طبقة WCF. لدي أيضًا طريقة تمديد عكسية (cameradatacontract.maptocamera) على طبقة الخدمة أيضًا.

في جوهرها ، أفعل ذلك في الطريقة الأولى ، لكن طريقة Todata هي طريقة تمديد لا تعرفها سوى طبقة WCF.

الأول (تعريض DTO) هو الأفضل بالنسبة لي. الأمر أبسط ، وسوف يعمل بشكل أسرع ، وسيكون من الأسهل فهمها وصيانتها. نظرًا لأن DTO ليس له أي اعتماد على كائن قاعدة البيانات ، فإنه لا يزال يحقق الهدف بسهولة من التبعيات.

أنا وضعت إلى/من طرق على DTOs نفسها:

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

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

وبهذه الطريقة ، لا يجب أن تعرف كائنات النطاق الخاصة بي عن DTOs.

هل خدماتك WCF إلى WCF؟

إذا كانوا بعد ذلك ، فيمكنك اختيار استخدام كائنات عملك كـ DTOs (طالما أن كائنات عملك هي جاهل). إذا فعلت هذا ، فإنني أوصي بتغيير فئة Cameradata إلى واجهة Icameradata وجعل الكاميرا تنفذ Icameradata. الحفاظ على السمات (DataContract وما إلى ذلك) على الواجهة.

ثم يمكنك تمرير كائن العمل من العميل إلى الخادم. كن على دراية بأي منطق على وجه التحديد من جانب العميل أو الخادم.

الصورة الأولى في بلدي مشاركة مدونة يوضح هنا مدى سهولة إعادة استخدام جانب كائنات كائنات العمل الخاصة بك (مربع الحوار هو ما يظهر عند القيام بـ "إضافة مرجع الخدمة"). يحتوي منشور المدونة على بعض المعلومات حول أحد مسكات إعادة استخدام كائنات Biz.

لا يمكنني معرفة ما الذي تحاول تحقيقه باستخدام ExposetorePorter ، لكنك على حق ، لا يبدو صحيحًا ، شخصياً سأضع طريقة على Ireporter التي تأخذ معلمة Icameradata ، ثم قم بتعيين تفاصيل المراسل داخل ذلك.

مصدر رائع للتعلم لهذه الأشياء DNRTV. شاهد كل شيء مع WCF في العنوان ولكن بشكل خاص WCF المتطرف من قبل ميغيل كاسترو!

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top