معماری MVP چیست؟ + نحوه پیاده سازی آن
معماری MVP یا همان مدل-نما-پرزنتر (Model-View-Presenter) یکی از مشتقات مدل معماری MVC ( مدل-نما-کنترلگر) است که اغلب برای طراحی رابط کاربری (UI) در اندروید مورد استفاده قرار می گیرد.
برای مثال فرض کنید که یک اپلیکیشن پخش کننده ویدیو طراحی کرده اید که ویژگی هایی نظیر اسلو موشن، زوم و ریورس کردن فیلم را دارد. حال با افزودن ویژگی های جدید به این اپلیکیشن، کدهای بخش پلی لیست ممکن است دچار خرابی و باگ شوند. نگران نباشید بهترین راه حل برای جلوگیری از خرابی ها و همچنین گسترش، تعمیر و نگهداری آسان اپلیکیشن استفاده از معماری MVP است. در ادامه این مطلب بخش های مختلف این معماری مورد بررسی قرار خواهیم داد.
معرفی معماری MVP
مدل معماری MVP همانند تمام الگوهای معماری دیگر در معرض گوناگونی و تجارب مختلف قرار دارد. بنابراین اجرای آن کمی مبهم به نظر می رسند، البته شما می توانید اجرای آن را مطابق با نیازهای خود اصلاح کنید. به طور کلی معماری MVP اهداف زیر را محقق می سازد:
- کدهای مربوط به نما (View) که در قالب لیست، دکمه، برچسب و تکست باکس از منطق بیزنس (Business Logic) به کاربر نشان داده می شوند را جدا کنید. این کدها در حقیقت از تعامل کاربران با نما که ما آن را Presenter می نامیم، ایجاد می شوند. داده هایی که در نما نمایش داده می شوند نیز باید از طریق یک ماژول جداگانه به نام Model ارائه شوند، در نتیجه یک کد قابل خواندن، قابل درک و قابل نگهداری خواهد بود.
- ارتباط میان نما و مدل باید از طریق Presenter صورت بپذیرد، در حقیقت نما و مدل نمی توانند مرجع یکدیگر باشند.
- برنامه نویسان با استفاده از این الگوی طراحی می توانند بدون هرگونه دخل و تصرفی در مولفه های دیگر، تغییرات مربوطه را در یک کامپوننت خاص اعمال کنند. علاوه بر این جایگزینی نما یا مدل با یک مولفه اجرایی دیگر نیز با استفاده از این معماری امکان پذیر خواهد بود.
- تولید کدهایی که می توان آنها را با فرآیند اتوماسیون مورد آزمایش قرار داد.
معماری MVP و اندروید
امکان توسعه ایده های متنوع در فریم ورک اندروید بسیار آسان است اما مدیریت این ساختار به علت وجود کدهای اسپاگتی (درهم تنیده) یا کلاس هایی با توابع مختلف بسیار پیچیده می شود. در حال حاضر اکتیویتی های اندروید (Android Activity)، توابع View را ارائه می دهند زیرا ما می توانیم کلاس هایی نظیر ()setContentView را در ()OnCreate اندروید بنویسیم.
اکتیویتی در همان زمان چرخه عمر مواردی از قبیل ()OnCreate و onResume() که ممکن است منطق بیزنس یا همان Presenter باشد را نیز حفظ خواهد کرد. مثال ساده زیر نحوه در هم تنیدگی آنها را نشان می دهد:
- نما: برای تعامل کاربران با رابط کاربری اپلیکیشن، listeners را رجیستر کنید.
- منطق بیزنس: برای پاسخگویی به تعامل کاربران با رابط کاربری اپلیکیشن، Action را اجرا کنید.
بیشتر برنامه نویسان معتقد هستند که دیباگ کردن (Debugging) یک اکتیویتی کد (Activity Code) که دارای چند خط کد متصل به کامپوننت UI و چند خط از منطق بیزنس است، کار بسیار دشوار و پیچیده ای به شمار می رود. البته در مدل MVP و بر اساس اصل یگانگی مسئولیت (SRP)، ما باید نقش یک نما یا Presenter را به یک Activity اختصاص دهیم. از آنجایی که اکتیویتی یک God Object است که امکان دسترسی به تمام خصوصیات یک پلتفرم را ارائه می دهد، بنابراین می توان از آن به عنوان Presenter نیز یاد کرد.
با توجه به این موضوع می توان Activity را به عنوان منطق بیزنس نیز در نظر گرفت و ما نیز می خواهیم نما را به عنوان یک ماژول که فقط قابلیت بارگذاری اجزای UI را دارد، تلقی کنیم.
نمونه اجرای معماری MVP در یک اپلیکیشن
در ادامه این بخش نحوه اجرای معماری MVP در یک اپلیکیشن پخش کننده ویدیو را با یکدیگر بررسی خواهیم کرد:
1- مدل (Model)
این بخش آسان ترین قسمت اجرای معماری اپلیکیشن است، ما از سرویس تامین کننده محتوا (Content Provider) اندروید برای اشتراک گذاری ویدیو استفاده کرده ایم. از آنجایی که Content Provider به صورت حاضر و آماده توسط اندروید ارائه می شود. بنابراین ما برای راه اندازی کوئری های اشتراک ویدیو فقط به چند خط کد نیاز خواهیم داشت. ما برای به روز رسانی اتوماتیک لیست ویدیو نیز از LoaderManager.LoaderCallbacks استفاده کرده ایم.
ما همچنین می توانیم در آینده دیتابیس MySQLite را جایگزین کنیم و از آنجایی که ساختار کدها در فرمت MVP است، هیچگونه آسیبی به آنها وارد نخواهد شد. برای مثال تعامل Presenter با مدل (Content Provider) توسط یک Manager Class جداگانه کنترل می شود و این Manager Class نیز از قوانین VideoListManager تبعیت می کند.
1 2 3 4 5 6 7 8 9 10 11 12 |
public interface VideoListManager { interface VideoListManagerListener { void onVideoListUpdate(VideoListInfo videoListInfo); } void getVideosWithNewSorting(int sortType); void registerListener(VideoListManagerListener videoListManagerListener); void unRegisterListener(); } |
جایگزینی sqLite با ContentProvider آسان خواهد بود، در حقیقت مادامی که Manager Class های جدید در Interface فوق اجرا شوند و لیست ویدیوهای Presenter را مطابق با فرمت درخواستی رابط به روز رسانی کنند، کدهای دیگر نیاز به هیچ تغییری نخواهند داشت.
2- نما (View)
ما ویدیوهای اپلیکیشن را با استفاده از ListView و ExpandableListView نمایش خواهیم داد. ما از یک رابط ViewMvp استفاده کردیم که نمای اصلی را به Presenter ارائه می دهد. این رابط در حقیقت با هدف ایجاد ارتباط بین نما و Presenter برای تعامل با کاربران مورد استفاده قرار خواهد گرفت.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
/* All Mvp Views must implement this interface It is a dumb View whose role is to present the view to the user and return the view to the presenter also handling the logic for communication between the presenter */ public interface ViewMvp { /* Get the root android view which is used by android mvp to present the view to the user this rootview is then used by the presenter to modify the root view or its child views */ View getRootView(); /* This method aggravates all the information about the mvp view which can be used by presenter by using the saved states in scenarios of android life cycle events */ Bundle getViewState(); } |
رابط ViewMvp که در بالا مشاهده می کنید یک رابط کلی محسوب می شود و کاربردهای دیگری نظیر بازگرداندن ListView نیز دارد که ما آنها را زیر رابط های ViewMvp نام گذاری کرده ایم. این رویکرد که ما View را بدون هیچ منطقی به عنوان حمل کننده UI تلقی کنیم و آن را در رابط اجرا کنیم به ما در موارد زیر کمک خواهد کرد:
- استفاده مجدد از UI
- اجرای یونیت تستینگ (Unit Testing) همزمان با اجرای رابط
- ارور کمتر در هنگاک بروز تغییرات UI
ما برای اجرای ListView به ویجت Adapters نیاز داریم، همچنین برای نشان دادن عناصر داخل ListView باید از الگوی ViewHolder استفاده کنیم.
1 2 3 4 5 6 7 8 9 10 11 |
@Override public void bindVideoList(VideoListInfo videoListInfo) { mVideoListAdapter.bindVideoList(videoListInfo); mVideoListAdapter.notifyDataSetChanged(); } @Override public View getRootView() { return mFragemntVideoListView; } |
تمام نماها (Views) متد bindVideoList را اجرا می کنند که برای بروز رسانی لیست ویدیو، اضافه کردن ویدیو، حذف، جستجو و دسته بندی مورد استفاده قرار می گیرد.
3- پرزنتر (Presenter)
پرزنتر بخش اصلی اپلیکیشن محسوب می شود به گونه ای که آغازکننده نما و مدل است. این بخش همچنین یک فریم ورک ارتباطی تنظیم می کند تا تعاملات کاربر و تغییرات دیتای مدل را کنترل کند. منطق جستجو، دسته بندی، اشتراک گذاری ویدیو، حذف، تغییر نام و این که در صورت انتخاب یک ویدیو توسط کاربر چه اتفاقی حاصل می شود، همگی به این بخش تعلق دارند. برخی از کاربردی های Presenter به شرح زیر است:
- تعامل با سیستم عامل
- رسیدگی به ورودی/درخواست کاربران و تولید نتیجه
- رسیدگی به تعاملات بین نما و مدل
- حفظ وضعیت اپلیکیشن
- Encapsulate کردن تمام منطق بیزینس اپلیکیشن
به عبارت دیگر می توان گفت بخش Presenter تمام کارهایی که شامل جزییات اجرای View یا مکانیزم ذخیره اطلاعات در Model نیست را انجام می هد. مثال زیر نحوه شروع نما و مدل را در متد ()OnCreate نشان می دهد:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
VideoListingViewImpl mVideoListingViewImpl; VideoListManagerImpl mVideoListManagerImpl; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mVideoListingViewImpl = new VideoListingViewImpl(this, null); //initializing the view setContentView(mVideoListingViewImpl.getRootView()); //setting the setContentView from the rootView returned mViewPager = mVideoListingViewImpl.getViewPager(); SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this); mSortingType = settings.getInt(SORT_TYPE_PREFERENCE_KEY, 3); mVideoListManagerImpl = new VideoListManagerImpl(this, mSortingType);// initialising the model mVideoListManagerImpl.registerListener(this); // registering the listerner to get video list update events } |
همانطور که در بالا به آن اشاره کردیم، فراگمنت ها (Fragments) و اکتیویتی ها (Activities) نقش Presenter را بر عهده دارند؛ البته بخش Presenter بیشتر برای مدیریت تعاملات مدل از طریق manager class مورد استفاده قرار می گیرد.
دیدگاهتان را بنویسید
برای نوشتن دیدگاه باید وارد بشوید.