تقنيات التعامل مع نموذج المجال المصاب بفقر الدم

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

سؤال

لقد قرأت بعض الأسئلة المتعلقة بنماذج المجال المصابة بفقر الدم وفصل الاهتمامات.ما هي أفضل التقنيات لتنفيذ/إرفاق منطق المجال على كائنات المجال المصابة بفقر الدم؟في وظيفتي، لدينا نموذج ضعيف جدًا، ونحن نستخدم حاليًا فئات "مساعدة" لتنفيذ قاعدة البيانات/منطق الأعمال على كائنات المجال.على سبيل المثال:

public class Customer
{
    public string Name {get;set;}
    public string Address {get;set;}
}

public class Product
{
    public string Name {get;set;}
    public decimal Price {get;set;}
}

public class StoreHelper
{
    public void PurchaseProduct(Customer c, Product p)
    {
         // Lookup Customer and Product in db
         // Create records for purchase
         // etc.
    }
}

عندما يحتاج التطبيق إلى إجراء عملية شراء، فإنه يقوم بإنشاء StoreHelper، واستدعاء الطريقة على كائنات المجال.بالنسبة لي، سيكون من المنطقي أن يعرف العميل/المنتج كيفية حفظ نفسه في أحد المستودعات، ولكن ربما لا تريد أساليب Save() على كائنات المجال.قد يكون من المنطقي أيضًا استخدام طريقة مثل Customer.Purchase(Product)، ولكن هذا يضع منطق المجال على الكيان.

فيما يلي بعض التقنيات التي صادفتها، ولست متأكدًا ما إذا كانت جيدة أم سيئة:

  1. يرث العميل والمنتج من فئة "الكيان"، والتي توفر عمليات CRUD الأساسية بطريقة عامة (ربما باستخدام ORM).
    • الايجابيات:سيحصل كل كائن بيانات تلقائيًا على عمليات CRUD، ولكن يتم ربطه بعد ذلك بقاعدة البيانات/ORM
    • سلبيات:وهذا لا يحل مشكلة العمليات التجارية على الكائنات، ويربط أيضًا جميع كائنات المجال بكيان أساسي قد لا يكون مناسبًا
  2. استخدم الفئات المساعدة للتعامل مع عمليات CRUD ومنطق الأعمال
    • هل يعقل أن يكون هناك DAOs لعمليات "قاعدة البيانات الخالصة"، ومساعدي أعمال منفصلين للعمليات الأكثر تحديدًا للأعمال؟
    • هل من الأفضل استخدام فئات مساعدة غير ثابتة أو ثابتة لهذا الغرض؟
    • الايجابيات:كائنات المجال غير مرتبطة بأي قاعدة بيانات/منطق عمل (فقر الدم تمامًا)
    • سلبيات:ليس OO جدًا، وليس من الطبيعي جدًا استخدام المساعدين في كود التطبيق (يشبه كود C)
  3. استخدم تقنية الإرسال المزدوج حيث يكون لدى الكيان طرق للحفظ في مستودع عشوائي
    • الايجابيات:الفصل الأفضل بين الاهتمامات
    • سلبيات:تحتوي الكيانات على بعض المنطق الإضافي المرفق (على الرغم من أنه منفصل)
  4. في الإصدار C# 3.0، يمكنك استخدام أساليب الامتداد لإرفاق أساليب CRUD/business بكائن المجال دون لمسه
    • هل هذا نهج صحيح؟ما هي إيجابيات / سلبيات؟
  5. تقنيات أخرى؟

ما هي أفضل التقنيات للتعامل مع هذا؟أنا جديد تمامًا على DDD (أنا أقرأ كتاب إيفانز - لذا ربما يفتح ذلك عيني)

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

المحلول

لقد كتب مارتن فاولر الكثير عن نماذج المجال، بما في ذلك نماذج المجال فقر الدم.لديه أيضًا أوصاف مختصرة (ومخططات فئة UML) للعديد من أنماط التصميم لنماذج المجال وقواعد البيانات التي قد تكون مفيدة: كتالوج "أنماط هندسة التطبيقات المؤسسية".

أود أن أقترح النظر في سجل نشط و مخطط البيانات أنماط.من وصف مشكلتك، يبدو أن الفئات المساعدة لديك تحتوي على قواعد المجال/العمل و تفاصيل تنفيذ قاعدة البيانات.

سيقوم Active Record بنقل منطق المجال المساعد ورمز قاعدة البيانات إلى كائنات المجال الأخرى (مثل ملف Entity الطبقة الأساسية).سيقوم مخطط البيانات بنقل منطق مجال المساعد إلى كائنات المجال ورمز قاعدة البيانات إلى كائن خريطة منفصل.سيكون أي من النهجين أكثر توجهاً نحو الكائنات من الفئات المساعدة ذات النمط الإجرائي.

يعتبر كتاب إريك إيفانز "التصميم الموجه بالمجال" ممتازًا.يصبح جافًا بعض الشيء، لكنه بالتأكيد يستحق ذلك.InfoQ لديه الكتاب المصغر "التصميم المعتمد على المجال بسرعة". هذه مقدمة جيدة لكتاب إيفانز.بالإضافة إلى أن "التصميم المعتمد على المجال بسرعة" متاح كملف PDF مجاني.

نصائح أخرى

لتجنب نموذج فقر الدم، قم بإعادة بناء الفئات المساعدة الخاصة بك:

المنطق مثل:
"Customer.PurchaseProduct(منتج المنتج، دفع الدفع)"،
"Customer.KillCustomer (قاتل شخص، سلاح سلاح)"
يجب أن تكون موجودة مباشرة في كائن مجال "العميل".

المنطق مثل:
"Customer.IsCustomerAlive()"
"Customer.IsCustomerHappy()"
يجب أن تذهب إلى المواصفات.

المنطق مثل:
""Customer.Create()"،"
""تحديث العميل ()"
ومن الواضح أن تذهب إلى المستودعات.

المنطق مثل:
"Customer.SerializeInXml()"
"Customer.GetSerializedCustomerSizeInBytes()"
يجب أن تذهب إلى الخدمات.

يجب أن يذهب المصممون المعقدون إلى المصانع.

هكذا أرى الأمر.سأكون سعيدًا إذا تمكن شخص ما من التعليق على فهمي لنهج DDD.


يحرر:

في بعض الأحيان - نموذج المجال فقر الدم لا ينبغي تجنبها.

قمت بتحرير إجابتي لإضافة أن DDD لا يتعلق بالتقاط الأنماط وإسقاطها.
DDD يدور حول الطريقة التي نفكر بها.

لقد فكرت دائمًا في نموذج المجال المصاب بفقر الدم باعتباره نمطًا مضادًا.من الواضح أن العميل سيشتري المنتجات، ويمكن إنشاء هذه القدرة من خلال تنفيذ الواجهة

Interface IPurchase
      Purchase(Product);

, ، لذلك يمكن لأي من كائنات المجال الخاص بك تنفيذ ذلك كما هو مطلوب.وبهذه الطريقة، يمكنك تقديم وظائف لكائنات المجال الخاص بك - وهو المكان الذي يجب أن تكون فيه بالضبط.

إحدى الطرق التي لم تذكرها هي استخدام AOP للتعامل مع الوصول إلى البيانات الخاصة بك.أحد الأمثلة على استخدامي الأخير لهذا النهج (على الرغم من تبسيطه إلى حد كبير لأغراض النشر) هو أنه كان لدي Account كيان المجال الذي كان له debit الطريقة، والتي تتضمن منطق الأعمال المطلوب لإجراء خصم ناجح من الحساب.

ملحوظة:كل التعليمات البرمجية هي Java مع تدوين AspectJ AOP...

public boolean debit(int amount) {
    if (balance - amount >= 0) {
        balance = balance - amount;
        return true;
    }
    return false;
}

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

pointcut debit(Account account,int amount) :
    execution(boolean Account.debit(int)) &&
    args(amount) &&
    target(account);

...وطبقت بعض النصائح:

after(Account account, int amount) returning (boolean result)  : debit(account,amount) {
    if (result) getAccountRepository().debit(account, amount);
}

في رأيي، يوفر هذا فصلًا جيدًا بين الاهتمامات، ويسمح لكيانات المجال الخاص بك بالتركيز بشكل كامل على منطق الأعمال الخاص بتطبيقك.

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