در اين صفحه ميخواهيم با الگوي MVVM بيشتر آشنا شويم.
اين الگو، الگوي معماري براي طراحي واسط كاربر است. Model – view – viewmodel (MVVM) یک الگوی معماری نرمافزاری است که جداسازی توسعه رابط کاربری گرافیکی - چه از طریق یک زبان نشانهگذاری یا کد رابط کاربری گرافیکی - از توسعه منطق کسبوکار یا پشتیبان را تسهیل میکند. منطق پایان به طوری که دیدگاه به هیچ پلتفرم مدل خاصی وابسته نباشد. viewmodel MVVM یک مبدل مقدار است، به این معنی که viewmodel مسئول نمایش (تبدیل) اشیاء داده از مدل است به گونه ای که اشیا به راحتی مدیریت و ارائه شوند. گونهای از الگوی طراحی مدل ارائه مارتین فاولر است. این توسط معماران مایکروسافت کن کوپر و تد پیترز به طور خاص برای ساده کردن برنامهنویسی رویداد محور رابطهای کاربری اختراع شد. این الگو در Windows Presentation Foundation (WPF) (سیستم گرافیکی دات نت مایکروسافت) و Silverlight (مشتق برنامه کاربردی اینترنتی WPF) گنجانده شد. جان گاسمن، یکی از معماران مایکروسافت WPF و Silverlight، MVVM را در وبلاگ خود در سال 2005 اعلام کرد.
Model-view-viewmodel همچنین به عنوان model-view-binder شناخته می شود، به ویژه در پیاده سازی هایی که شامل پلتفرم دات نت نیستند. ZK (یک چارچوب برنامه کاربردی وب که به زبان جاوا نوشته شده است) و KnockoutJS (یک کتابخانه جاوا اسکریپت) از model–view–binder استفاده میکنند.
از این الگو زمانی استفاده کنید که نیاز دارید مدلها را به نمایش دیگری برای نما تبدیل کنید. به عنوان مثال، می توانید از یک مدل view برای تبدیل یک تاریخ به یک رشته با قالب تاریخ، یک اعشار به یک رشته با قالب ارز یا بسیاری از تبدیل های مفید دیگر استفاده کنید.
این الگو به خوبی MVC را تحسین می کند. بدون مدلهای view، احتمالاً کد تبدیل مدل به مشاهده را در کنترلکننده مشاهده خود قرار میدهید. با این حال، کنترلکنندههای view در حال حاضر کارهای زیادی انجام میدهند: مدیریت viewDidLoad و سایر رویدادهای چرخه حیات مشاهده، مدیریت تماسهای مشاهده از طریق IBActions و چندین کار دیگر نیز.
این منجر به چیزی می شود که توسعه دهندگان به شوخی از آن به عنوان "MVC: Massive View Controller" یاد می کنند.
اجزاي الگوي MVVM
مدل
مدل یا به یک مدل دامنه اشاره دارد که محتوای حالت واقعی را نشان می دهد (رویکرد شی گرا)، یا به لایه دسترسی به داده که نشان دهنده محتوا است (رویکرد داده محور)
ويو
همانطور که در الگوهای model-view-controller (MVC) و model-view-presenter (MVP)، نما، ساختار، طرحبندی، ظاهر چیزی است که کاربر روی صفحه میبیند، نمایشی از مدل را نمایش میدهد و تعامل کاربر با نما را دریافت میکند (کلیکهای ماوس، ورودی صفحهکلید، حرکات ضربه روی صفحه، و غیره)، و مدیریت این موارد را از طریق اتصال داده (ویژگیها، تماسهای رویداد) به مدل view ارسال میکند.
مدل ويو
مدل view یک انتزاع از نما است که ویژگی ها و دستورات عمومی را نشان می دهد. به جای کنترلکننده الگوی MVC یا ارائهدهنده الگوی MVP، MVVM دارای یک کلاسور است که ارتباط بین view و ویژگیهای محدود آن در مدل view را خودکار میکند. مدل view به عنوان حالتی از داده ها در مدل توصیف شده است.
تفاوت اصلی بین مدل view و Presenter در الگوی MVP این است که ارائه دهنده به یک view ارجاع دارد، در حالی که مدل view اینطور نیست. در عوض، یک view مستقیماً به ویژگیهای مدل view متصل میشود تا بهروزرسانیها را ارسال و دریافت کند.
بايندر
داده های اعلامی و اتصال فرمان در الگوی MVVM ضمنی هستند. در پشته راه حل مایکروسافت، بایندر یک زبان نشانه گذاری به نام XAML است. بایندر توسعهدهنده را از موظف به نوشتن منطق صفحه دیگر برای همگامسازی مدل و نما آزاد میکند. هنگامی که خارج از پشته مایکروسافت پیادهسازی میشود، وجود یک فنآوری پیوند دادههای اعلامی چیزی است که این الگو را ممکن میسازد و بدون یک بايندر، معمولاً میتوان به جای آن از MVP یا MVC استفاده کرد.
ديتا بايندينگ یک طرفه:
وقتی اطلاعات مدل تغییر میکنه، بصورت خودکار اطلاعاتی که ویوو داره نمایش میده هم تغییر میکنه.
ديتا بايندينگ دو طرفه:
توی این روش وقتی اطلاعات نمایشی توی View تغییر میکنه، اطلاعات مدل بصورت خودکار و آنی هم تغییر پیدا میکنه.
برای حذف تقریباً تمام کدهای رابط کاربری گرافیکی ("code-behind") از لایه view، با استفاده از توابع اتصال داده در WPF (بنیاد ارائه ویندوز) طراحی شده است تا جداسازی توسعه لایه دید از بقیه الگو را بهتر تسهیل کند. بهجای اینکه توسعهدهندگان تجربه کاربری (UX) را مجبور به نوشتن کد رابط کاربری گرافیکی کنند، میتوانند از زبان نشانهگذاری چارچوب (مانند XAML) استفاده کنند و پیوندهای دادهای را به مدل view ایجاد کنند، که توسط توسعهدهندگان برنامه نوشته و نگهداری میشود. جداسازی نقشها به طراحان تعاملی اجازه میدهد تا به جای برنامهنویسی منطق تجاری، بر نیازهای UX تمرکز کنند. بنابراین، لایه های یک برنامه کاربردی را می توان در جریان های کاری متعدد برای بهره وری بالاتر توسعه داد. حتی زمانی که یک توسعهدهنده منفرد بر روی کل پایه کد کار میکند، جداسازی مناسب نما از مدل مؤثرتر است، زیرا رابط کاربری معمولاً بر اساس بازخورد کاربر نهایی اغلب و در اواخر چرخه توسعه تغییر میکند.
الگوی MVVM تلاش می کند تا هر دو مزیت جداسازی توسعه عملکردی ارائه شده توسط MVC را به دست آورد، در حالی که از مزایای اتصال داده ها و چارچوب با اتصال داده ها تا حد امکان به مدل کاربردی خالص استفاده می کند. نتیجه این است که مدل و چارچوب تا آنجا که ممکن است عملیات را هدایت می کند، منطق برنامه را که مستقیماً نمایش را دستکاری می کند، حذف یا به حداقل می رساند.
اين نكته مدنظر هست كه MVVM یک نسخه شخصیسازی شده از MVC هست. هدف اصلی MVC جداسازی و تفکیک قسمتهای بیربط برنامه هست (Separation of Concerns). کنترلر توی MVC کنترل جریان اطلاعات بین مدل و ویو را به عهده دارد. توی MVC یک ویو میتواند به صورت مستقیم اطلاعات مدل را بخواند و نمایش دهد. در برنامهنویسی وب از الگوی MVC بیشتر برای قسمت بکاند استفاده میشود.
در MVVM مدل و ویو هیچ شناختی از هم دیگر ندارند. ویو مدل برخلاف کنترلر MVC، یک کنترلگر نیست. بلکه نقش یک پل بین مدل و ویو را بر عهده دارد. یک رابط بین اطلاعات مدل و اطلاعات ویو. توسط تکنیکی به اسم Data Binding که با اون مدل و ویو میتوانند بطور مستقیم با هم در ارتباط باشند. با Data Binding ویومدل، مدل و ویو بصورت خودکار و راحت از تغییرات با خبر میشن.
Data Binding ویو مدل میتواند بزرگترین نقص MVVM باشد. به گفته سازندهی این الگو تکنیک Data Binding میتواند مقدار زیاد از حافظه را اشغال کند و استفاده از ان برای عملیات ساده UI یک افراط هست. پروژههای بزرگی که از MVVM استفاده میکنند اجرای اولیه سنگینی دارند. برای همین از این الگو بیشتر برای برنامههای تک صفحهای (Single Page Application) استفاده میشود.
مزایای استفاده از الگوی MVVM
اگر یک مدل پیادهسازی موجود وجود داشته باشد که منطق تجاری موجود را در بر بگیرد، تغییر آن میتواند دشوار یا خطرناک باشد. در این سناریو، view model به عنوان یک آداپتور برای کلاسهای مدل عمل میکند و شما را قادر میسازد تا از ایجاد هرگونه تغییر عمده در کد مدل خودداری کنید.
توسعهدهندگان میتوانند بدون استفاده از view، آزمایشهای واحد را برای مدل view و مدل ایجاد کنند. تستهای واحد برای مدل view میتوانند دقیقاً همان عملکردی را اعمال کنند که توسط view استفاده میشود.
رابط کاربری برنامه را می توان بدون لمس کد دوباره طراحی کرد، مشروط بر اینکه نما به طور کامل در XAML پیاده سازی شود. بنابراین، یک نسخه جدید از view باید با مدل view موجود کار کند.
طراحان و توسعه دهندگان می توانند به طور مستقل و همزمان بر روی اجزای خود در طول فرآیند توسعه کار کنند. طراحان می توانند روی نما تمرکز کنند، در حالی که توسعه دهندگان می توانند روی مدل view و اجزای مدل کار کنند.
چارچوب های MVVM از قبل موجود
اکنون که ما ایدهای داریم که MVVM چیست، لازم نیست چرخ را دوباره اختراع کنید. تعدادی چارچوب خارج از جعبه وجود دارد که MVVM را پیاده سازی می کند. بدون ترتیب خاصی:
MVVM Light Toolkit: این یک جعبه ابزار بسیار محبوب است که حاوی پشتیبانی خارج از جعبه برای نمای پایه، دستورات، پیامرسانی و قالبهای پروژه برای شروع است. از هر دو پروژه WPF و Silverlight پشتیبانی می کند.
SilverlightFX: اهداف اعلام شده برای این فریم ورک عبارتند از: فعال کردن مشخصات اجمالی واسط های کاربر، امکان جداسازی آسان تر دیدگاه و کد، و ارائه یک چارچوب ناب.
کالیبرن: Caliburn یک فریمورک محبوب viewmodel-first است که از WPF و Silverlight پشتیبانی می کند. با این حال، فراتر از MVVM، یک چارچوب کاربردی کامل است.
n مسیر: یکی دیگر از چارچوبهای MVVM، این کتابخانه برای «فرمانهای معکوس» منحصربهفرد است که اجازه میدهد دستورات اتصال به رویدادها در view را انجام دهد، نه اینکه view به سادگی دستورات را به viewmodel ارسال کند.
MicroModels: یک رویکرد بسیار ناب و سبک به MVVM.
کامپوزیت WPF/Prism: علیرغم نام، این فریم ورک از WPF و Silverlight پشتیبانی می کند. در حالی که به طور مستقیم پیاده سازی های MVVM را ارائه نمی دهد، پشتیبانی و راهنمایی زیادی برای نوشتن برنامه های کاربردی از جمله دستورات، تجمع رویداد، مدیریت منطقه و موارد دیگر ارائه می دهد.
اتصال View Models به Views
با استفاده از قابلیت Data Binding Xamarin.Forms می توان مدل های View را به View ها متصل کرد. روشهای زیادی وجود دارد که میتوان برای ساخت نماها و مشاهده مدلها و مرتبط کردن آنها در زمان اجرا استفاده کرد. این رویکردها به دو دسته تقسیم میشوند که بهعنوان ترکیب اول view و ترکیب اول دیدگاه مدل شناخته میشوند. انتخاب بین ترکیب view first و view model first ترکیب یک موضوع اولویت و پیچیدگی است. با این حال، همه رویکردها یک هدف مشترک دارند، و آن این است که view یک مدل view به ویژگی BindingContext آن اختصاص داده شود.
با ترکیب دیدگاه اول، برنامه از نظر مفهومی از نماهایی تشکیل شده است که به مدلهای نمایشی که به آنها وابسته هستند متصل میشوند. مزیت اصلی این رویکرد این است که ساخت اپلیکیشنهای با جفت آزاد و واحد قابل آزمایش را آسان میکند زیرا مدلهای view هیچ وابستگی به خود نماها ندارند. همچنین درک ساختار برنامه با پیروی از ساختار بصری آن آسان است، به جای اینکه مجبور باشید اجرای کد را ردیابی کنید تا بفهمید کلاس ها چگونه ایجاد و مرتبط می شوند. علاوه بر این، نمای اولین ساختوساز با سیستم ناوبری Xamarin.Forms که مسئول ساخت صفحات در هنگام پیمایش است، همسو میشود، که باعث میشود اولین ترکیب مدل view پیچیده و با پلتفرم ناهماهنگ شود.
با ترکیب اول مدل view، برنامه از نظر مفهومی از مدلهای view تشکیل شده است، با سرویسی که مسئول مکان یابی نمای یک مدل view است. ترکیب اول مدل View برای برخی از توسعهدهندگان طبیعیتر است، زیرا ایجاد نما را میتوان انتزاع کرد و به آنها اجازه میدهد بر ساختار منطقی غیر UI برنامه تمرکز کنند. علاوه بر این، این امکان را فراهم می کند که مدل های view توسط سایر مدل های view ایجاد شوند. با این حال، این رویکرد اغلب پیچیده است و درک نحوه ایجاد و مرتبط کردن بخشهای مختلف برنامه ممکن است دشوار شود.
به روز رسانی نماها در پاسخ به تغییرات در مدل یا مدل نمای زیربنایی
همه مدلهای view و کلاسهای مدل که برای یک view قابل دسترسی هستند باید رابط INotifyPropertyChanged را پیادهسازی کنند. پیادهسازی این رابط در یک مدل view یا کلاس مدل به کلاس اجازه میدهد تا اعلانهای تغییر را برای کنترلهای وابسته به داده در نما، زمانی که مقدار ویژگی اساسی تغییر میکند، ارائه دهد.
برنامه ها باید برای استفاده صحیح از اعلان تغییر دارایی، با رعایت شرایط زیر طراحی شوند:
در صورت تغییر ارزش دارایی عمومی، همیشه یک رویداد PropertyChanged را افزایش دهید. تصور نکنید که افزایش رویداد PropertyChanged به دلیل آگاهی از نحوه اتصال XAML نادیده گرفته می شود.
همیشه یک رویداد PropertyChanged برای هر ویژگی محاسبه شده ای که مقادیر آن توسط سایر ویژگی ها در مدل view یا مدل استفاده می شود، افزایش می دهد.
همیشه رویداد PropertyChanged را در پایان متدی که تغییر خاصیت ایجاد میکند، یا زمانی که شی در حالت امن است، بالا میرود. بالا بردن رویداد، عملیات را با فراخوانی همزمان کنترل کننده های رویداد قطع می کند. اگر این در وسط یک عملیات اتفاق بیفتد، ممکن است زمانی که شی در وضعیت ناامن و تا حدی به روز شده باشد، آن را در معرض توابع پاسخ به تماس قرار دهد. علاوه بر این، ممکن است تغییرات آبشاری توسط رویدادهای PropertyChanged فعال شوند. تغییرات آبشاری معمولاً به تکمیل بهروزرسانیها نیاز دارند تا قبل از اینکه تغییر آبشاری اجرا شود.
اگر ویژگی تغییر نکرد، هرگز یک رویداد PropertyChanged را مطرح نکنید. این بدان معناست که قبل از بالا بردن رویداد PropertyChanged باید مقادیر قدیمی و جدید را با هم مقایسه کنید.
اگر یک ویژگی را مقداردهی اولیه می کنید، هرگز رویداد PropertyChanged را در طول سازنده یک مدل view بالا نمی برید. کنترلهای محدود به داده در نما برای دریافت اعلانهای تغییر در این مرحله مشترک نخواهند شد.
هرگز بیش از یک رویداد PropertyChanged با آرگومان نام ویژگی یکسان در یک فراخوانی همزمان یک متد عمومی یک کلاس افزایش نمییابد. به عنوان مثال، با توجه به یک ویژگی NumberOfItems که ذخیره پشتیبان آن فیلد _numberOfItems است، اگر متدی در طول اجرای یک حلقه، _numberOfItems را پنجاه بار افزایش دهد، پس از اتمام کار، فقط باید یک بار اعلان تغییر ویژگی را در ویژگی NumberOfItems افزایش دهد. برای روشهای ناهمزمان، رویداد PropertyChanged را برای یک نام مشخصه در هر بخش همزمان از یک زنجیره ادامه ناهمزمان بالا ببرید.
تعامل رابط کاربری با استفاده از دستورات و رفتارها
در برنامه های تلفن همراه، اقدامات معمولاً در پاسخ به یک اقدام کاربر، مانند کلیک روی دکمه، فراخوانی می شوند که می تواند با ایجاد یک کنترل کننده رویداد در فایل پشت کد اجرا شود. با این حال، در الگوی MVVM، مسئولیت اجرای عمل بر عهده مدل view است و باید از قرار دادن کد در کد پشت خودداری شود.
دستورات روشی مناسب برای نمایش اقداماتی ارائه میدهند که میتوانند به کنترلهای موجود در رابط کاربری متصل شوند. آنها کدی را که عمل را اجرا میکند، محصور میکنند و کمک میکنند تا آن را از نمایش بصریاش در نما جدا نگه دارند. Xamarin.Forms شامل کنترلهایی است که میتوانند به صورت اعلانی به یک فرمان متصل شوند و این کنترلها هنگام تعامل کاربر با کنترل، فرمان را فراخوانی میکنند.
رفتارها همچنین به کنترلها اجازه میدهند تا به طور آشکار به یک فرمان متصل شوند. با این حال، رفتارها را می توان برای فراخوانی عملی استفاده کرد که با طیف وسیعی از رویدادهای مطرح شده توسط یک کنترل مرتبط است. بنابراین، رفتارها به بسیاری از سناریوهای مشابه کنترلهای دارای فرمان پاسخ میدهند، در حالی که انعطافپذیری و کنترل بیشتری را ارائه میکنند. علاوه بر این، رفتارها همچنین می توانند برای مرتبط کردن اشیاء یا روش های فرمان با کنترل هایی استفاده شوند که به طور خاص برای تعامل با دستورات طراحی نشده اند.
اجرای رفتارها
رفتارها به کنترلهای UI اجازه میدهند بدون نیاز به زیر کلاسبندی، عملکردها را به آنها اضافه کنند. در عوض، عملکرد در یک کلاس رفتار پیادهسازی میشود و به کنترل متصل میشود که گویی بخشی از خود کنترل است. رفتارها شما را قادر می سازند کدی را پیاده سازی کنید که معمولاً باید به صورت کد پشتی بنویسید، زیرا مستقیماً با API کنترل در تعامل است، به گونه ای که می تواند به طور خلاصه به کنترل متصل شود و برای استفاده مجدد در بیش از یک نما یا برنامه در زمینه MVVM، رفتارها یک رویکرد مفید برای اتصال کنترل ها به دستورات هستند.
رفتاری که از طریق ویژگی های متصل به یک کنترل متصل می شود، به عنوان رفتار پیوست شناخته می شود. سپس رفتار می تواند از API آشکار عنصری که به آن متصل است برای افزودن عملکرد به آن کنترل یا سایر کنترل ها در درخت بصری نما استفاده کنند.
نتيجه گيري
الگوها یک مبحث ثابت و تغییر ناپذیر نیستن. میتوانیم انها را شخصیسازی و یا با الگوهای دیگر مخلوط کنیم. همانطور که فریمورکی مثل Vue.js فقط قسمتی از این الگو را پیادهسازی کرده است. یک الگو برايش فرقی نمیکند که از چه زبان و چه فریمورکی استفاده میشود. الگوها فقط راه حلهای عمومی برای مشکلات عمومی ارائه میدهند. استفاده از هر الگويي باید با دقت صورت گيرد. یک الگو میتواند نظم فوقالعادهای به یک برنامه بدهد و همچنین یک برنامهی ساده را دچار پیچیدگیهای غیر منطقی کند.
1- https://docs.microsoft.com/en-us/xamarin/xamarin-forms/enterprise-application-patterns/mvvm
2- https://ditty.ir/posts/mvvm-pattern/XpAPJ
3- https://whatis.techtarget.com/definition/Model-View-ViewModel#:~:text=Model%2DView%2DViewModel%20(MVVM)%20is%20a%20software%20design,logic%20and%20user%20interface%20controls.&text=The%20pattern%20is%20often%20used,)%2C%20which%20runs%20on%20Microsoft's%20.
4- https://www.wintellect.com/model-view-viewmodel-mvvm-explained/
5- https://www.raywenderlich.com/34-design-patterns-by-tutorials-mvvm
6- https://docs.microsoft.com/en-us/xamarin/xamarin-forms/enterprise-application-patterns/mvvm
7- https://books.zkoss.org/zk-mvvm-book/8.0/introduction_of_mvvm.html
8- https://www.tutorialspoint.com/mvvm/index.html
این مطلب، بخشی از تمرینهای درس معماری نرمافزار در دانشگاه شهیدبهشتی است.