كيفية اختيار هندسة iOS المناسبة (الجزء 2)

MVC أو MVP أو MVVM أو VIPER أو VIP

يمكنك استشارة الجزء الأول هنا.

أبنية دائرة الرقابة الداخلية الرئيسية

لمحة موجزة.

MVC

طبقات MVC كالتالي:

M: منطق الأعمال ، طبقة الشبكة وطبقة الوصول إلى البيانات

الخامس: UI Layer (أشياء UIKit ، قصص ، Xibs)

ج: ينسق الوساطة بين النموذج والعرض.

لفهم MVC ، يجب أن نفهم السياق الذي اخترع فيه. تم اختراع MVC في أيام تطوير الويب القديمة ، حيث لا توجد طرق عرض لعروض المشاهدة. في الأزمنة القديمة في كل مرة نحتاج فيها إلى تغيير مرئي في الموقع ، يقوم المتصفح بإعادة تحميل HTML بالكامل مرة أخرى. في ذلك الوقت لم يكن هناك مفهوم لحالة العرض التي يتم حفظها وحفظها.

على سبيل المثال ، كان هناك بعض المطورين الذين اختلطوا في نفس ملف HTML ، PHP والوصول إلى قاعدة البيانات. لذلك كان الدافع الرئيسي لـ MVC هو فصل طبقة العرض عن طبقة النموذج. هذا زاد من اختبار طبقة النموذج. من المفترض في MVC ، يجب ألا تعرف طبقة العرض والنموذج شيئًا عن بعضها البعض. لجعل هذا ممكنًا ، تم اختراع طبقة وسيطة تسمى وحدة التحكم. كان هذا هو SRP الذي تم تطبيقه.

مثال على دورة MVC:

  1. يتم تشغيل إجراء / حدث المستخدم في View Layer (على سبيل المثال: Refresh Action) ويتم توصيل هذا الإجراء إلى Controller
  2. وحدة التحكم التي تطلب البيانات إلى طبقة النموذج
  3. نموذج إرجاع البيانات إلى المراقب المالي
  4. يقول المراقب للعرض تحديث حالته مع البيانات الجديدة
  5. عرض تحديث حالته

أبل MVC

في نظام التشغيل iOS ، يقترن جهاز العرض View بنظام UIKit وطريقة عرض دورة الحياة ، لذلك فهو ليس MVC خالصًا. ومع ذلك ، في تعريف MVC ، لا يوجد شيء يمكن القول إنه لا يمكن لوحدة التحكم معرفة طريقة العرض المحددة أو النموذجية المحددة. هدفه الرئيسي هو فصل مسؤوليات طبقة النموذج عن طبقة العرض حتى نتمكن من إعادة استخدامها واختبار طبقة النموذج بمعزل عن غيرها.

يحتوي ViewController على العرض ويملك الطراز. المشكلة هي أننا استخدمنا لكتابة رمز وحدة التحكم وكذلك رمز العرض في ViewController.

غالبًا ما تخلق MVC مشكلة التحكم في Massive View Controller ، لكن هذا يحدث فقط ويصبح شيئًا خطيرًا في التطبيقات ذات التعقيد الكافي.

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

  • استخراج منطق VC لفئات أخرى مثل الجدول طريقة عرض مصدر البيانات طرق وتفويض لملفات أخرى باستخدام نمط تصميم المفوض.
  • قم بإنشاء فصل أكثر وضوحًا للمسؤوليات باستخدام التركيبة (على سبيل المثال تقسيم VC إلى أدوات التحكم في العرض الفرعي).
  • استخدم نمط تصميم المنسق لإزالة مسؤولية تنفيذ منطق التنقل في VC
  • استخدم فئة مجمّع DataPresenter تقوم بتغليف المنطق وتحويل نموذج البيانات إلى إخراج بيانات يمثل البيانات المقدمة للمستخدم النهائي.

MVC مقابل MVP

كيف يمكنك أن ترى الرسم البياني لل MVP يشبه الى حد بعيد MVC

لقد كانت MVC خطوة للأمام ، لكنها لا تزال تتسم بالغياب أو الصمت حول بعض الأشياء.

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

في MVC ، أعتقد أنه لا يوجد ما يشير إلى أن وحدة التحكم يجب ألا تعرف التنفيذ المحدد للعرض (الغياب).

كان HTML جزءًا من طبقة العرض وكثير من الحالات كانت غبية مثل اللعنة. في بعض الحالات ، يستقبل الأحداث فقط من المستخدم ويعرض المحتوى المرئي من واجهة المستخدم الرسومية.

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

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

في MVP و MVVM ، يجب أن تكون طبقة العرض غبية كما هي دون أي منطق أو ذكاء ، وفي iOS ، يجب أن تكون وحدة التحكم في العرض جزءًا من طبقة العرض. حقيقة أن العرض غبي يعني أنه حتى منطق العرض التقديمي يبقى خارج طبقة العرض.

إحدى مشكلات MVC هي أنه من غير الواضح أين يجب أن يظل منطق العرض التقديمي. إنه ببساطة صامت حول ذلك. هل يجب أن يكون منطق العرض التقديمي في طبقة العرض أو في طبقة النموذج؟

إذا كان دور النموذج هو مجرد توفير البيانات "الأولية" ، فهذا يعني أن الكود في طريقة العرض سيكون:

النظر في المثال التالي: لدينا مستخدم ، مع الاسم الأول واسم العائلة. في طريقة العرض ، نحتاج إلى عرض اسم المستخدم باسم "اسم العائلة ، الاسم الأول" (مثل "Flores، Tiago").

إذا كان دور النموذج هو توفير البيانات "الأولية" ، فهذا يعني أن الكود في طريقة العرض سيكون:

واسمحوا firstName = userModel.getFirstName ()
اسمح lastName = userModel.getLastName ()
nameLabel.text = اسم العائلة + "،" + اسم العائلة

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

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

اسمك = userModel.getDisplayName ()
nameLabel.text = الاسم

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

عادةً في تطبيقات MVP ، تكون طريقة العرض مخفية خلف واجهة / بروتوكول ويجب ألا تكون هناك أي إشارات إلى UIKit في مقدم العرض.

شيء آخر أن نأخذ في الاعتبار هو التبعيات متعدية.

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

تتغير الطبقات المختلفة أيضًا لأسباب مختلفة وبمعدلات مختلفة. لذلك عند تغيير طبقة لا تريد أن يتسبب ذلك في تأثيرات / مشكلات ثانوية في الطبقات الأخرى.

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

وبالتالي فإن العقود (البروتوكولات) تخلق فصلًا بين الطبقات.

MVP مقابل MVVM

مخطط MVVM

أحد الاختلافات الرئيسية بين MVP و MVVM هو أن MVP في MVP يتواصل مع طريقة العرض من خلال واجهات ، وفي MVVM يتم توجيه العرض إلى تغييرات البيانات والأحداث.

في MVP نجعل الربط اليدوي بين المقدم والعرض باستخدام واجهات / بروتوكولات.
في MVVM ، نجعل الربط التلقائي للبيانات باستخدام شيء مثل RxSwift ، KVO أو استخدام آلية مع الأدوية العامة والإغلاق.

في MVVM ، لا نحتاج حتى إلى عقد (على سبيل المثال: java interface / iOS protocol) بين ViewModel و View لأننا نتواصل عادة من خلال نمط تصميم المراقب.

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

فكر في منطق العرض التقديمي لمؤشر التحميل. في MVP يقوم مقدم العرض بـ ViewProtocol.showLoadingIndicator. في MVVM قد يكون هناك خاصية isLownload في ViewModel. تكتشف طبقة عرض خلال ربط بيانات تلقائي عندما تتغير هذه الخاصية وتحديث نفسها. MVP أكثر ضرورة من MVVM لأن مقدم العرض يعطي الأوامر.

تتعلق MVVM بتغييرات البيانات أكثر من الطلبات المباشرة ، ونقوم بإنشاء ارتباطات بين تغييرات البيانات وعرض التحديثات. إذا استخدم RxSwift ونموذج البرمجة التفاعلية الوظيفية جنبًا إلى جنب مع MVVM ، فقد جعلنا الكود أقل حتمية وأكثر إعلانًا.

MVVM أسهل في الاختبار من MVP لأن MVVM يستخدم نمط تصميم المراقب الذي ينقل البيانات بين المكونات بطريقة منفصلة.
حتى نتمكن من الاختبار فقط من خلال النظر في التغييرات في البيانات فقط من خلال مقارنة بين كائنين بدلاً من إنشاء تذبذبات المكالمات الأساليب لاختبار الاتصال بين View و Presenter.

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

الجزء الثاني ينتهي هنا. جميع ردود الفعل هو موضع ترحيب. الجزء الثالث سيتحدث عن VIPER ، VIP ، البرمجة التفاعلية ، المقايضات ، القيود والمعنى السياقي.

شكرا لقرائتك! إذا حببت هذا المقال ، يرجى التصفيق
حتى يتمكن الآخرون من قراءتها أيضًا :)