نموذج – عرض – نموذج العرض

يُعد نمط MVVM ( نموذج-عرض-نموذج العرض ) تصميمًا معماريًا متعدد الطبقات في برامج الكمبيوتر، وهو يُسهل فصل تطوير واجهة المستخدم الرسومية (GUI؛ العرض ) - سواء كان ذلك عبر لغة ترميز أو كود واجهة المستخدم الرسومية - عن تطوير منطق الأعمال أو منطق الواجهة الخلفية ( النموذج ) بحيث لا يعتمد العرض على أي منصة نموذج محددة.
يُعدّ نموذج العرض في نمط MVVM مُحوِّلًا للقيم، [ 1 ] أي أنه مسؤول عن عرض (تحويل) كائنات البيانات من النموذج بطريقة تُسهّل إدارتها وعرضها. وبهذا المعنى، يُعتبر نموذج العرض نموذجًا أكثر منه عرضًا ، ويتولى معظم (إن لم يكن كل) منطق عرض الواجهة. [ 1 ] قد يُطبّق نموذج العرض نمط الوسيط ، مُنظِّمًا الوصول إلى منطق الواجهة الخلفية حول مجموعة حالات الاستخدام التي يدعمها العرض.
نمط MVVM هو أحد أنماط تصميم نموذج العرض التقديمي (Presentation Model) لمارتن فاولر . [ 2 ] [ 3 ] يشبه نمط MVVM نمط نموذج العرض التقديمي (Model-view-presenter) إلى حد كبير . وقد ابتكره مهندسا مايكروسوفت، كين كوبر وتيد بيترز، خصيصًا لتبسيط برمجة واجهات المستخدم القائمة على الأحداث . تم دمج هذا النمط في مؤسسة عرض ويندوز (WPF) (نظام رسومات .NET من مايكروسوفت ) وسيلفرلايت ، وهو مشتق من تطبيقات الإنترنت الخاصة بـ WPF. [ 3 ] أعلن جون جوسمان، مهندس مايكروسوفت في WPF وسيلفرلايت، عن نمط MVVM على مدونته عام 2005. [ 3 ] [ 4 ]
يُشار إلى نموذج العرض-نموذج العرض أيضًا باسم نموذج العرض-رابط العرض ، خاصةً في التطبيقات التي لا تستخدم منصة .NET . يستخدم كلٌ من ZK ، وهو إطار عمل لتطبيقات الويب مكتوب بلغة Java ، ومكتبة JavaScript المسماة KnockoutJS ، نموذج العرض-رابط العرض. [ 3 ] [ 5 ] [ 6 ]
مكونات نمط MVVM
- نموذج
- يشير النموذج إما إلى نموذج المجال ، الذي يمثل محتوى الحالة الحقيقية (نهج موجه نحو الكائنات)، أو إلى طبقة الوصول إلى البيانات ، التي تمثل المحتوى (نهج يركز على البيانات).
- منظر
- كما هو الحال في نمطي MVC و MVP ، فإن العرض هو بنية وتخطيط ومظهر ما يراه المستخدم على الشاشة. [ 7 ] يعرض العرض تمثيلاً للنموذج ويستقبل تفاعل المستخدم معه (نقرات الماوس، إدخال لوحة المفاتيح، إيماءات النقر على الشاشة، إلخ)، ثم يُحيل معالجة هذه التفاعلات إلى نموذج العرض عبر ربط البيانات (الخصائص، ردود استدعاء الأحداث، إلخ) المُعرّف لربط العرض بنموذج العرض.
- عرض النموذج
- نموذج العرض هو تجريد للعرض، يكشف عن الخصائص والأوامر العامة. وبدلاً من وحدة التحكم في نمط MVC، أو المُقدِّم في نمط MVP، يحتوي MVVM على رابط ، يُؤتمت عملية التواصل بين العرض وخصائصه المرتبطة في نموذج العرض. وقد وُصف نموذج العرض بأنه حالة البيانات في النموذج. [ 8 ]
- يتمثل الاختلاف الرئيسي بين نموذج العرض والمُقدِّم في نمط MVP في أن المُقدِّم لديه مرجع إلى العرض، بينما لا يمتلك نموذج العرض ذلك. بدلاً من ذلك، يرتبط العرض مباشرةً بخصائص نموذج العرض لإرسال واستقبال التحديثات. ولضمان كفاءة هذه العملية، يتطلب الأمر تقنية ربط أو إنشاء شيفرة نمطية جاهزة لإجراء الربط. [ 7 ]
- في البرمجة الكائنية التوجه ، يمكن الإشارة أحيانًا إلى نموذج العرض على أنه كائن نقل البيانات . [ 9 ]
- مجلد
- يُعد ربط البيانات والأوامر التصريحي جزءًا لا يتجزأ من نمط MVVM. في حزمة حلول مايكروسوفت ، تُستخدم لغة ترميز تُسمى XAML كأداة ربط . [ 10 ] تُعفي هذه الأداة المطور من كتابة التعليمات البرمجية النمطية لمزامنة نموذج العرض والعرض. عند تطبيق هذا النمط خارج حزمة مايكروسوفت، فإن وجود تقنية ربط البيانات التصريحي هو ما يجعله ممكنًا، [ 5 ] [ 11 ] وبدون أداة الربط، سيلجأ المطور عادةً إلى نمط MVP أو MVC، مما يستلزم كتابة المزيد من التعليمات البرمجية النمطية (أو توليدها باستخدام أداة أخرى).
الأساس المنطقي
صُمم نمط MVVM لإزالة جميع أكواد واجهة المستخدم الرسومية تقريبًا (" الكود البرمجي ") من طبقة العرض، وذلك باستخدام وظائف ربط البيانات في WPF (مؤسسة عرض ويندوز) لتسهيل فصل تطوير طبقة العرض عن باقي أجزاء النمط. [ 3 ] فبدلًا من مطالبة مطوري تجربة المستخدم بكتابة أكواد واجهة المستخدم الرسومية، يمكنهم استخدام لغة ترميز الإطار (مثل XAML ) وإنشاء روابط بيانات لنموذج العرض، الذي يكتبه ويصونه مطورو التطبيقات. يتيح فصل الأدوار لمصممي التفاعل التركيز على احتياجات تجربة المستخدم بدلًا من برمجة منطق الأعمال. وبالتالي، يمكن تطوير طبقات التطبيق في مسارات عمل متعددة لزيادة الإنتاجية. حتى عندما يعمل مطور واحد على قاعدة الكود بأكملها، فإن الفصل السليم بين العرض والنموذج يكون أكثر إنتاجية، لأن واجهة المستخدم تتغير عادةً بشكل متكرر وفي مراحل متأخرة من دورة التطوير بناءً على ملاحظات المستخدم النهائي.
يسعى نمط MVVM إلى الجمع بين مزايا فصل التطوير الوظيفي التي يوفرها نمط MVC، والاستفادة من مزايا ربط البيانات والإطار البرمجي من خلال ربط البيانات بنموذج التطبيق الأساسي قدر الإمكان. [ 3 ] [ 4 ] [ 12 ] يستخدم هذا النمط الرابط، ونموذج العرض، وميزات التحقق من البيانات في طبقات الأعمال للتحقق من صحة البيانات الواردة. والنتيجة هي أن النموذج والإطار البرمجي يُديران معظم العمليات قدر الإمكان، مما يُلغي أو يُقلل من منطق التطبيق الذي يُعالج العرض مباشرةً (مثل الكود البرمجي المُرفق).
نقد
انتقد جون غوسمان نمط MVVM وتطبيقاته في استخدامات محددة، مصرحًا بأن MVVM قد يكون "مبالغًا فيه" عند إنشاء واجهات مستخدم بسيطة. أما بالنسبة للتطبيقات الأكبر حجمًا، فيعتقد أن تعميم نموذج العرض مسبقًا قد يكون صعبًا، وأن ربط البيانات على نطاق واسع قد يؤدي إلى انخفاض الأداء. [ 13 ]
التطبيقات
أطر عمل .NET
- مجموعة أدوات مجتمع .NET
- أفالونيا
- كاليبورن، كاليبورن.مايكرو
- شينوك. ديناميك إم في في إم مفتوح المصدر
- DevExpress MVVM
- مشروع DotVVM مفتوح المصدر
- FreshMvvm
- قنديل البحر
- مجموعة أدوات Mugen MVVM
- مجموعة أدوات MVVMLight
- MvvmCross
- MvvmZero
- مكتبة بريزم
- راسكل
- واجهة المستخدم التفاعلية
- منصة أونو - مفتوحة المصدر
مكتبات مكونات الويب
- مايكروسوفت فاست
- Omi.js
أطر عمل جافا
أطر عمل جافا سكريبت
أطر عمل للغة C++ و XAML (ويندوز)
- C++/WinRT
- Xamlcc
أمثلة
فيما يلي أمثلة بسيطة لتطبيق نمط MVVM.
لغة سي++
هذا مثال باستخدام لغة C++ .
export module wikipedia . examples . mvvm ;استيراد std ؛باستخدام std :: string ;تصدير مساحة الاسم ويكيبيديا :: أمثلة :: mvvm {class Model { private : int counter = 0 ; public : [[ nodiscard ]] int getCounter () const noexcept { return counter ; }void increment () noexcept { counter ++ ; }void decrement () noexcept { counter -- ; } };class ViewModel { private : Model & model ; public : explicit ViewModel ( Model & m ) : model { m } {}void incrementCounter () noexcept { model.increment ( ) ; }void decrementCounter ( ) noexcept { model.decrement ( ); }[[ nodiscard ]] int getCounterValue () const noexcept { return model . getCounter (); } };class View { private : ViewModel & viewModel ; public : explicit View ( ViewModel & vm ) : viewModel { vm } {}void run () { string input ; while ( true ) { std :: println ( "العداد: {}" , viewModel.getCounterValue ( )); std :: print ( "أدخل الأمر (i = زيادة، d=إنقاص، q=خروج): " ); std :: getline ( std :: cin , input );إذا كان ( المدخل == " i " ) { viewModel.incrementCounter (); } وإلا إذا كان ( المدخل == " d" ) { viewModel.decrementCounter ( ); } وإلا إذا كان ( المدخل == "q" ) { break ; } وإلا { std :: println ( "أمر غير معروف." ); } } } } ;}بعد ذلك، يمكن تشغيل التطبيق على النحو التالي:
استيراد wikipedia.examples.mvvm ؛باستخدام مساحة الاسم wikipedia :: أمثلة :: mvvm ;int main ( int argc , char * argv []) { Model m ; ViewModel vm ( m ); View v ( vm ); v . run (); return 0 ; }سي شارب
هذا مثال باستخدام لغة C# .
Model.cs :
namespace Wikipedia.Examples.Mvvm ;public class Model { public int Counter { get ; private set ; } = 0 ;public void Increment () => Counter ++ ; public void Decrement () => Counter -- ; }ViewModel.cs :
namespace Wikipedia.Examples.Mvvm ;public class ViewModel { private readonly Model _model ;public ViewModel ( Model model ) { _model = model ; }public void IncrementCounter () = > _model.Increment ( ) ; public void DecrementCounter ( ) => _model.Decrement ( ) ; public int CounterValue => _model.Counter ; }View.cs :
namespace Wikipedia.Examples.Mvvm ;باستخدام النظام ؛public class View { private readonly ViewModel _viewModel ;public View ( ViewModel viewModel ) { _viewModel = viewModel ; }public void Run ( ) { string input = String.Empty ; while ( true ) { Console.WriteLine ( $ "العداد: {_viewModel.CounterValue}" ) ; Console.Write ( " أدخل الأمر (i=زيادة، d=إنقاص، q=خروج): " ) ; input = Console.ReadLine ( ); switch ( input ) { case "i" : _viewModel.IncrementCounter (); break ; case " d" : _viewModel.DecrementCounter ( ) ; break ; case " q" : return ; default : Console.WriteLine ( "أمر غير معروف . " ) ; break ; } } } }بعد ذلك، يمكن تشغيل التطبيق Main.cs على النحو التالي:
namespace Wikipedia.Examples ;باستخدام Wikipedia.Examples.Mvvm ؛public class Main { public static void Main () { Model model = new (); ViewModel viewModel = new ( model ); View view = new ( viewModel ); view . Run (); } }جافا
هذا مثال باستخدام لغة جافا .
Model.java :
package org.wikipedia.examples.mvvm ;public class Model { private int counter = 0 ;public int getCounter () { return counter ; }public void increment () { counter ++ ; }public void decrement () { counter -- ; } }ViewModel.java :
package org.wikipedia.examples.mvvm ;public class ViewModel { private final Model model ;public ViewModel ( Model model ) { this . model = model ; }public void incrementCounter () { model . increment (); }public void decrementCounter () { model . decrement (); }public int getCounterValue () { return model . getCounter (); } }View.java :
package org.wikipedia.examples.mvvm ;استيراد java.util.Scanner ؛public class View { private final ViewModel viewModel ;public View ( ViewModel viewModel ) { this . viewModel = viewModel ; }public void run ( ) { Scanner stdin = new Scanner ( System.in ) ; String input ; while ( true ) { System.out.printf ( " العداد : %d%n" , viewModel.getCounterValue ( ) ) ; System.out.print ( " أدخل الأمر (i=زيادة، d=إنقاص، q=خروج): " ) ; input = stdin.nextLine ( ); switch ( input ) { case " i" : viewModel.incrementCounter ( ) ; break ; case " d " : viewModel.decrementCounter (); break ; case " q" : return ; default : System.out.println ( " أمر غير معروف . " ) ; } } } }بعد ذلك، يمكن تشغيل التطبيق Main.java على النحو التالي:
package org.wikipedia.examples ;استيراد org.wikipedia.examples.mvvm.* ;public class Main { public static void main ( String [] args ) { Model m = new Model (); ViewModel vm = new ViewModel ( m ); View v = new View ( vm ); v . run (); } }الصدأ
هذا مثال باستخدام لغة Rust .
استخدم std :: io ؛pub struct Model { counter : i32 , }impl Model { pub fn new () -> Self { Model { counter : 0 } }pub fn get_counter ( & self ) -> i32 { self . counter }pub fn increment ( & mut self ) { self . counter += 1 ; }pub fn decrement ( & mut self ) { self . counter -= 1 ; } }pub struct ViewModel <' a > { model : & ' a mut Model , }impl <' a > ViewModel <' a > { pub fn new ( model : & ' a mut Model ) -> Self { Self { model } }pub fn increment_counter ( & mut self ) { self . model . increment (); }pub fn decrement_counter ( & mut self ) { self . model . decrement (); }pub fn get_counter_value ( & self ) -> i32 { self . model . get_counter () } }pub struct View <' a > { view_model : & ' a mut ViewModel <' a > , }impl <' a > View <' a > { pub fn new ( view_model : & ' a mut ViewModel <' a > ) -> Self { Self { view_model } }pub fn run ( & mut self ) { loop { println! ( "العداد: {}" , self . view_model . get_counter_value ());print! ( "أدخل الأمر (i=زيادة، d=إنقاص، q=خروج): " ); io :: stdout (). flush (). unwrap ();let mut input : String = String :: new (); io :: stdin (). read_line ( & mut input ). unwrap (); let input : String = input . trim ();match input { "i" = > self.view_model.increment_counter ( ) , " d" => self.view_model.decrement_counter ( ) , "q" => break , _ => println ! ( "أمر غير معروف." ) , } } } }بعد ذلك، يمكن تشغيل التطبيق main.rs على النحو التالي:
mod mvvm ;استخدم mvvm ::{ Model , View , ViewModel };fn main () { let mut m : Model = Model :: new (); let mut vm : ViewModel = ViewModel :: new ( & mut m ); let mut v : View = View :: new ( & mut vm ); v . run (); }انظر أيضاً
مراجع
- 1 2 سميث، جوش؛ وآخرون . "فكرة: نموذج MVVM يُلغي 99% من الحاجة إلى محولات القيمة" . مجموعات جوجل .
- ↑ مارتن فاولر (19 يوليو 2004). "نمط تصميم نموذج العرض التقديمي" . MartinFowler.com.
- 1 2 3 4 5 6 سميث، جوش (فبراير 2009). "تطبيقات WPF باستخدام نمط تصميم Model-View-ViewModel" . مجلة MSDN .
- 1 2 جوسمان، جون (8 أكتوبر 2005). "حكايات من العميل الذكي: مقدمة لنمط Model/View/ViewModel لبناء تطبيقات WPF" .
- 1 2 ماسي، سيمون (9 أبريل 2011). "أنماط العرض في ZK" . تم الاسترجاع في 24 مارس 2012 .
- ↑ ستيف ساندرسون. "KnockoutJS" .
- 1 2 "نمط MVVM" . msdn.microsoft.com . 4 أكتوبر 2012. تم الاطلاع عليه بتاريخ 29 أغسطس 2016 .
- ↑ بيت وايسبرود. "نمط نموذج-عرض-نموذج عرض لـ WPF: نهج آخر" . مؤرشف من الأصل في 1 فبراير 2008.
- ↑ مايكروسوفت (3 أبريل 2024). "برنامج تعليمي: إنشاء واجهة برمجة تطبيقات ويب باستخدام ASP.NET Core" .
- ↑ وايلدرموث، شون (11 مايو 2010). "ربط بيانات مؤسسة عرض ويندوز: الجزء 1" . مايكروسوفت . تم الاسترجاع في 24 مارس 2012 .
- ↑ "ZK MVVM" . بوتيكس . تم الاطلاع عليه بتاريخ 24 مارس 2012 .
- ↑ كارل شيفليت. "تعلم WPF MV-VM" . مؤرشف من الأصل في 13 أبريل 2009. تم الاطلاع عليه في 5 يونيو 2009 .
- ↑ غوسمان، جون (4 مارس 2006). "حكايات من العميل الذكي: مزايا وعيوب MV-VM" . تحدي مهارات الذكاء الاصطناعي .
- أنماط تصميم البرمجيات
- النمط المعماري (علوم الحاسوب)
- مصطلحات .NET
