Architecture-center: ما الفرق بين ProductsCommandHandler (CQRS) و ProductRepository (القوس التقليدي)؟

تم إنشاؤها على ١٥ نوفمبر ٢٠١٩  ·  5تعليقات  ·  مصدر: MicrosoftDocs/architecture-center

أهلا،
شكرا لكتابة هذا المقال على CQRS. أحاول أن أفهم كيف يبدو التنفيذ وكنت أطلع على الأمثلة. يبدو رمز مستودع التخزين النموذجي المقدم في المثال مشابهًا جدًا للطريقة المعتادة لكتابة الريبو باستثناء اصطلاح التسمية. على سبيل المثال ، أعتقد أن المستودع الموضح أدناه هو نفسه ProductsCommandHandler وربما يكون الاختلاف الوحيد هو عدم وجود GetProduct هنا والذي نضيفه عادةً. هل يمكن أن توضح لي ما لم أحصل عليه هنا؟

public class ProductRepository {
  void AddNewProduct(Product newProduct) {
    ...
  }
  void RateProduct(int productId, int userId, int rating) {
    var product = repository.Find(productId);
    if (product != null)
    {
      product.RateProduct(userId, rating);
      repository.Save(product);
    }
  }
}

تفاصيل المستند

لا تقم بتحرير هذا القسم.

Pri1 architecture-centesvc assigned-to-author cloud-fundamentalsubsvc product-question triaged

التعليق الأكثر فائدة

martinmthomas في الحقيقة معالج الأوامر ليس مستودعا. يستخدم المستودع.

يُقصد بمعالج الأوامر "معالجة الأوامر الفعلية ، إذا كان ذلك مناسبًا". في المثال ، تتلقى فئة ProductsCommandHandler IRepository<Product> في مُنشئها.

لنفترض أن المستخدم سيقوم بتقييم المنتج 5555 إلى 4 نجوم.

  • يرى المستخدم واجهة. لنفترض أن صفحة ويب (يمكن أن تكون برنامجًا محليًا. exe أو أيًا كان ، دعنا نتخيل موقعًا على الويب).
  • ينقر المستخدم على زر. لنفترض أن هذا يؤدي إلى انتقال AJAX POST إلى مسار / معدل باستخدام البيانات {"product":"5555","stars":4}
  • يحتوي مسار POST على وحدة تحكم. وحدة التحكم هذه مرتبطة بعملية "كتابة" لأنها تأتي من مكالمة POST.
  • ستعمل وحدة التحكم هنا في الأسلوب الكلاسيكي على تحميل مستودع المنتج الكلاسيكي وتحميل المنتج 5555. ثم أخبر المنتج "تم تصنيفك الآن بـ 4 نجوم" وحفظه.
  • في هذا الأسلوب ، تُنشئ وحدة التحكم الأمر RateProduct وتعبئ المنتج 5555 ، النجوم 4. في المثال ، تملأ أيضًا من هو التصنيف.
  • في هذه اللحظة ، ترسل وحدة التحكم "الأمر" إلى نموذج الكتابة. لديك خياران هنا: استدعاء معالج أوامر أو وضعه في قائمة الانتظار.
  • لنفترض أنه ليس لديك قائمة انتظار. ستحصل بعد ذلك على CommandHandler في وحدة التحكم الخاصة بك (ربما عن طريق إدخال التبعية) وقم فقط بوضع الأمر هناك: h.Handle (c)؛ حيث c هو الأمر RateProduct.
  • لنفترض أن لديك قائمة انتظار. يمكنك بعد ذلك الحصول على قائمة الانتظار في وحدة التحكم الخاصة بك (ربما عن طريق حقن التبعية) وقم فقط بإدراج الأمر هناك: q.Queue (c)؛
  • في هذه الحالة الأخيرة ، سيقوم مستمع قائمة الانتظار بإخراج الأمر من قائمة الانتظار واستدعاء معالج الأوامر بدلاً من ذلك.
  • كخيار thirs (موصى به) ، لا تختار وحدة التحكم الخاصة بك ما إذا كان الأمر يتم معالجته بشكل متزامن (احصل على المعالج) أو بشكل غير متزامن (احصل على قائمة الانتظار) ولكن يجب أن تستخدم "نهجًا عامًا" وهو استخدام ناقل الأوامر حيث الأوامر يتم وضعها. قل أن ناقل الأمر هو b ، ثم ستفعل b.Send (c) ؛ حيث c هو الأمر RateProduct.
  • باستخدام هذا النهج الثالث ، يمكنك وضع معالج الأوامر في نهاية الحافلة ، ويمكنك تكوين البرامج الوسيطة "لإخراج الأمر من الحافلة ووضعه في قائمة الانتظار".

إذن هناك 3 خيارات: أ) احصل على المعالج ، ب) احصل على قائمة الانتظار ، ج) احصل على حافلة واتركها تقرر إرسال الأمر إلى المعالج أو إلى قائمة الانتظار.

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

إذن ، معالج الأوامر هو الذي - كما يقول اسمه - "يتعامل مع الأمر" الذي جاء من مكان ما (وحدة تحكم ويب html ، وحدة تحكم API ، سطر أوامر ، أيًا كان) الذي تم إرساله كنية وهو CommandHandler (الذي ينتمي إلى جانب الكتابة) الذي يقرر ما يجب فعله بهذا الأمر.

على سبيل المثال ، يمكن لـ CommandHandler استخدام الريبو للحصول على المنتج وتعيين الحالة والحفظ (كما في المثال) ، ولكن يمكنه أيضًا الكتابة في سجل الأحداث أو تشغيل العناصر لتحديث جوانب القراءة أو تشغيل الموصلات الخارجية أو أي شيء آخر.

واجهة المستخدم المستندة إلى المهام لتقييم المنتج ووحدة التحكم الخاصة به لتكون AGNOSTIC "حيث" يتم وضع نظام النجوم / التصنيف أو تخزينه. تخيل أنك تصمم نظامًا من البداية وأن فئة المنتج تحتوي بالفعل على طريقة RateProduct () كما في المثال. حسن.

ولكن ... ماذا لو كان لديك نظام قديم هناك مع نهج "قديم" للمنتج. في "النموذج" (أي: Business Mind) لا يوجد "تصنيف" للمنتج. بدلاً من ذلك ، يريد رجل التسويق "إضافة" تصنيف إلى المنتج الحالي ولكن جميع الشركات توافق على أن هذا "شيء خارجي". هل ستستخدم مستودع المنتج؟ أو ربما تخزين مساعد آخر حتى لا "تلمس" مستودع المنتج والمنتج الذي تم اختباره بالكامل والذي تم اختباره بالكامل؟

إذا كنت تستخدم أوامر ، فإنه لا يمانع في الكتابة تحكم. سيرسل الويب و API و CLI فقط "الأمر" إلى معالج الأوامر (إما مباشرة ، عبر قائمة الانتظار أو عبر ناقل الأوامر الذي سيوجه بدوره إلى المعالج أو إلى قائمة الانتظار) وينسون. ثم سيقرر معالج الأمر ما يجب فعله باستخدام "RateProductCommand" في نقطة مركزية وصغيرة من شفرة المصدر الخاصة بك ، وهذا يفصل الطريقة التي يتم بها التعامل مع هذا من كود التطبيق ، وبالتالي يكتسب قابلية التحكم.

ثم يقرر المعالج ما إذا كان من المناسب استخدام ProductRepository أو أي طريقة أخرى لتخزين "تصنيف المنتج".

لذا ، للإجابة:

CommandHandler => ليس له علاقة بالكائنات. إنه يتعامل مع "نوايا المستخدم" (التي قد تكون في النهاية لتغيير الكيانات ؛ لذلك على الأرجح يستخدم معالج الأوامر مستودعًا).
المستودع => التخزين الفعلي لكيان معين.

نأمل في المساعدة.
تشافي.

ال 5 كومينتر

martinmthomas شكرا لك على سؤالك! سنراجع ونقدم تحديثًا حسب الاقتضاء.

MikeWasson أي أفكار هنا؟

AB # 160217 - شكرًا على الإبلاغ - هذه المشكلة قيد المراجعة

martinmthomas في الحقيقة معالج الأوامر ليس مستودعا. يستخدم المستودع.

يُقصد بمعالج الأوامر "معالجة الأوامر الفعلية ، إذا كان ذلك مناسبًا". في المثال ، تتلقى فئة ProductsCommandHandler IRepository<Product> في مُنشئها.

لنفترض أن المستخدم سيقوم بتقييم المنتج 5555 إلى 4 نجوم.

  • يرى المستخدم واجهة. لنفترض أن صفحة ويب (يمكن أن تكون برنامجًا محليًا. exe أو أيًا كان ، دعنا نتخيل موقعًا على الويب).
  • ينقر المستخدم على زر. لنفترض أن هذا يؤدي إلى انتقال AJAX POST إلى مسار / معدل باستخدام البيانات {"product":"5555","stars":4}
  • يحتوي مسار POST على وحدة تحكم. وحدة التحكم هذه مرتبطة بعملية "كتابة" لأنها تأتي من مكالمة POST.
  • ستعمل وحدة التحكم هنا في الأسلوب الكلاسيكي على تحميل مستودع المنتج الكلاسيكي وتحميل المنتج 5555. ثم أخبر المنتج "تم تصنيفك الآن بـ 4 نجوم" وحفظه.
  • في هذا الأسلوب ، تُنشئ وحدة التحكم الأمر RateProduct وتعبئ المنتج 5555 ، النجوم 4. في المثال ، تملأ أيضًا من هو التصنيف.
  • في هذه اللحظة ، ترسل وحدة التحكم "الأمر" إلى نموذج الكتابة. لديك خياران هنا: استدعاء معالج أوامر أو وضعه في قائمة الانتظار.
  • لنفترض أنه ليس لديك قائمة انتظار. ستحصل بعد ذلك على CommandHandler في وحدة التحكم الخاصة بك (ربما عن طريق إدخال التبعية) وقم فقط بوضع الأمر هناك: h.Handle (c)؛ حيث c هو الأمر RateProduct.
  • لنفترض أن لديك قائمة انتظار. يمكنك بعد ذلك الحصول على قائمة الانتظار في وحدة التحكم الخاصة بك (ربما عن طريق حقن التبعية) وقم فقط بإدراج الأمر هناك: q.Queue (c)؛
  • في هذه الحالة الأخيرة ، سيقوم مستمع قائمة الانتظار بإخراج الأمر من قائمة الانتظار واستدعاء معالج الأوامر بدلاً من ذلك.
  • كخيار thirs (موصى به) ، لا تختار وحدة التحكم الخاصة بك ما إذا كان الأمر يتم معالجته بشكل متزامن (احصل على المعالج) أو بشكل غير متزامن (احصل على قائمة الانتظار) ولكن يجب أن تستخدم "نهجًا عامًا" وهو استخدام ناقل الأوامر حيث الأوامر يتم وضعها. قل أن ناقل الأمر هو b ، ثم ستفعل b.Send (c) ؛ حيث c هو الأمر RateProduct.
  • باستخدام هذا النهج الثالث ، يمكنك وضع معالج الأوامر في نهاية الحافلة ، ويمكنك تكوين البرامج الوسيطة "لإخراج الأمر من الحافلة ووضعه في قائمة الانتظار".

إذن هناك 3 خيارات: أ) احصل على المعالج ، ب) احصل على قائمة الانتظار ، ج) احصل على حافلة واتركها تقرر إرسال الأمر إلى المعالج أو إلى قائمة الانتظار.

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

إذن ، معالج الأوامر هو الذي - كما يقول اسمه - "يتعامل مع الأمر" الذي جاء من مكان ما (وحدة تحكم ويب html ، وحدة تحكم API ، سطر أوامر ، أيًا كان) الذي تم إرساله كنية وهو CommandHandler (الذي ينتمي إلى جانب الكتابة) الذي يقرر ما يجب فعله بهذا الأمر.

على سبيل المثال ، يمكن لـ CommandHandler استخدام الريبو للحصول على المنتج وتعيين الحالة والحفظ (كما في المثال) ، ولكن يمكنه أيضًا الكتابة في سجل الأحداث أو تشغيل العناصر لتحديث جوانب القراءة أو تشغيل الموصلات الخارجية أو أي شيء آخر.

واجهة المستخدم المستندة إلى المهام لتقييم المنتج ووحدة التحكم الخاصة به لتكون AGNOSTIC "حيث" يتم وضع نظام النجوم / التصنيف أو تخزينه. تخيل أنك تصمم نظامًا من البداية وأن فئة المنتج تحتوي بالفعل على طريقة RateProduct () كما في المثال. حسن.

ولكن ... ماذا لو كان لديك نظام قديم هناك مع نهج "قديم" للمنتج. في "النموذج" (أي: Business Mind) لا يوجد "تصنيف" للمنتج. بدلاً من ذلك ، يريد رجل التسويق "إضافة" تصنيف إلى المنتج الحالي ولكن جميع الشركات توافق على أن هذا "شيء خارجي". هل ستستخدم مستودع المنتج؟ أو ربما تخزين مساعد آخر حتى لا "تلمس" مستودع المنتج والمنتج الذي تم اختباره بالكامل والذي تم اختباره بالكامل؟

إذا كنت تستخدم أوامر ، فإنه لا يمانع في الكتابة تحكم. سيرسل الويب و API و CLI فقط "الأمر" إلى معالج الأوامر (إما مباشرة ، عبر قائمة الانتظار أو عبر ناقل الأوامر الذي سيوجه بدوره إلى المعالج أو إلى قائمة الانتظار) وينسون. ثم سيقرر معالج الأمر ما يجب فعله باستخدام "RateProductCommand" في نقطة مركزية وصغيرة من شفرة المصدر الخاصة بك ، وهذا يفصل الطريقة التي يتم بها التعامل مع هذا من كود التطبيق ، وبالتالي يكتسب قابلية التحكم.

ثم يقرر المعالج ما إذا كان من المناسب استخدام ProductRepository أو أي طريقة أخرى لتخزين "تصنيف المنتج".

لذا ، للإجابة:

CommandHandler => ليس له علاقة بالكائنات. إنه يتعامل مع "نوايا المستخدم" (التي قد تكون في النهاية لتغيير الكيانات ؛ لذلك على الأرجح يستخدم معالج الأوامر مستودعًا).
المستودع => التخزين الفعلي لكيان معين.

نأمل في المساعدة.
تشافي.

كما ذكر xmontero ، فإن ProductsCommandHandler و

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

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات