تلاشی برای پیدا کردن یک پترن توسعه در اندروید
پینوشت: اگر با MVC و دیزاین پترن آشنا نیستید لطفا به پاسخ اول مراجعه کنید تا اطلاعات کافی رو به دست بیارید، سپس به این پاسخ برگردید و در بحث شرکت کنید.
سوال اساسی اینه که ما چطور میتونیم از مدل MVC توی برنامهنویسی اندروید استفاده کنیم؟
وقتی ما داریم مثلا پایتون کار میکنیم این کار خیلی سادهست چون الگوی خاصی برای قرار دادن کدهای مختلف نداریم و میتونیم mvc رو پیاده کنیم. اما توی اندروید viewها بصورت xml در layout هستن. از طرفی ما activity رو داریم که از یک سو کارِ view رو انجام میده از سوی دیگه بخش اعظمی از کار controller داخل اون انجام میشه.
دلیل اینکه کار view رو انجام میده اینه که منطق نمایش توی life cycleهای اکتیویتی اتفاق میفته و از طرف دیگه بسیاری از رفتارهای کنترلی نیاز به context اکتیویتی دارن بنابراین منطقیه تصور کنیم توسعه دهندههای اندروید هم معتقد بودن این دسته از فعالیتها باید توی activity انجام بشه (اگر فکر میکنید اشتباه میکنم تصحیح کنید)
پس انگار عملا اندروید طوری توسعه داده نشده که بشه view و controller رو جدا کرد.
برای مدل خیلی پیچیدگی نداره. چون مدل همونه که توی جاواست و میشه به همون طریق عمل کرد. برای مدل من به این راهکار رسیدم که پکیج جداگانهای رو در نظر بگیرم و ساختارها و POJOها رو اونجا قرار بدم. از طرفی کلاسهایی که شامل ساختار لیستها میشه رو هم من مدل در نظر میگیرم (نظر شما هم همینه؟).
اما باز هم نمیشه به یک برداشت واحد از توسعه mvc رسید.
شاید این بحث پیش بیاد که اصلا چه اصراریه mvc توسعه بدیم؟ دلیلش برای من اینه که بالاخره باید یک الگوی طراحی داشته باشیم. شاید وقتی برای خودمون کار میکنیم نیاز نباشه ولی در نهایت اکثریت جامعه برنامهنویس در تعامل با هم و در گروهها کار خواهند کرد و باید از الگوها استفاده کنن. ضمن اینکه حتی وقتی برای خودمون هم کار میکنیم استفاده از الگوها تست رو ساده میکنه. بعدا هم که برمیگردیم راحتتر متوجه میشیم چه کردیم و...
من خیلی جستجو کردم و الگویی که توی فرومهای خارجی خیلی ازش صحبت میشه همین mvc هست و آگهیهای کار هم بعضا دانش mvc رو جزء شرایط (یا ترجیحات) خودشون قرار دادن.
اما مشکل من اینه که نمیتونم به یک الگوی مشخص برای توسعه mvc برسم. نمونههای سورس کد هم که هست یا تفاوتهای بنیادی داره با همدیگه مثلا این کد رو با این کد مقایسه کنید:
اولی به طور کل activity رو ui حساب نکرده و با مدل خاصی که کد زده ui رو کاملا تبدیل به controller کرده. که البته این کار خیلی زیرکانه و حرفهایه ولی از طرفی ممکنه بین سایر برنامهنویسها مشترک نباشه و بیشتر کارو پیچیده کنه.
لینک دوم از طرف دیگه یک پکیج به اسم viewController ساخته و activity ها رو اونجا قرار داده. یعنی باز نیومده view و controller رو جدا کنه. یه کارایی هم کرده که چون کامنت نذاشته خیلی مشخص نیست. از یکسری interface استفاده کرده که بخشی از پیچیدگی controller رو تقسیم کنه بین کلاسها اما دقیقا مشخص نیست چرا و چطور.
و یا اینکه الگوشون خیلی مشخص نیست. شاید فهمیدن خودِ کد ساده باشه ولی اینکه از چه الگویی پیروی میکنه چندان مشخص نیست.
قبلا راجع به mvc بحثهایی شده داخل انجمن که اینجا میتونید پیگیری کنید. اما اون بحث هم به نتیجه عملی نرسید. استاد در یکجایی از اون بحث گفتن:
من به شدت مخالفم. چون MVC همانطور که گفتم یک Design Pattern هست و Design Pattern ها مثل آچار می مونن، مطمئناً با یک آچار 18 نمیشه یک پیچ آلن رو باز و بسته کرد. MVC هم اینجا نقش آچار 18 رو داره و اندروید نقش پیچ آلن. چرا؟ چون اندروید از لایه دیتا خاصی قرار نیست استفاده کنه که همه می افته گردن webservice. در بعضی جاها با سایر Design Pattern ها مثل Singleton , Builder, Factory و ... در تناقضه. لایه V وجود نداره و خودش به عنوان XML در اندروید استفاده میشه. به دلیل Dynamic بودن کنترل برنامه های اندروید ( بر خلاف وب ) لایه کنترل بسیار پیچیده میشه و در نهایت مزاحمت ایجاد می کنه.
من با این بخش که MVC شاید بهترین گزینه برای اندروید نباشه موافقم ولی درحال حاضر من جایگزینی براش پیدا نمیکنم و نهایتا باید یک دیزاین پترنی پیدا کنیم که بشه بصورت واحد توی اندروید ازش استفاده کنیم و اصطلاحا dirty code نداشته باشیم.
این تاپیک رو ایجاد کردم که دو تا کار کنیم:
یکی اینکه ایدههامون رو برای چطور پیادهکردن MVC توی اندروید بگیم. اگر شما از MVC (یا چیزی شبیه به اون که خودتون بهش رسیدید) استفاده میکنید راجع بهش صحبت کنید تا بصورت سیستماتیک بررسی کنیم و شاید بشه به عنوان روشی استاندارد همه ازش استفاده کنیم.
دوم اینکه دوستان با سابقه بگن از چه روشها و پترنهایی استفاده میکنن؟ شرکتهایی که در اونها گروهی روی پروژه کار میکنن بر اساس چه الگویی نرمافزار اندروید توسعه میدن؟
نمیدونم چقدر با دیزاین پترن(الگوی طراحی) و واژه MVC آشنا هستید. اگر خیلی آشنایی ندارید توصیه میکنم این مجموعه پستها رو مطالعه کنید.
اگر حوصله یا زمان کافی ندارید من توضیحات مختصری رو همینجا میدم که شاید خیلی دقیق نباشه اما میتونه کمک کنه با بحث آشنا بشید.
دیزاین پترن یا الگوی طراحی به مجموعه قواعد و قوانینی میگن که کمک میکنه ما با یکسری دغدغههای شناخته شده برنامهنویسی سیستماتیک برخورد کنیم.
مثلا ممکنه توی یک پروژه ما تعداد زیادی instance داشته باشیم که اشتراکات زیادی دارن. تعداد بالای این نمونهها میتونه به حافظه فشار بیاره و حتی باعث memory leak بشه. از طرفی هم پردازش همزمانشون به پردازنده فشار میاره و مصرف باتری رو هم زیاد میکنه. برای حل این مشکل هرکسی یک ایدهای ممکنه داشته باشه اما یک راه حل پذیرفته شده و بهینه استفاده از Flyweight Pattern هست. Flyweight الگوییه که اگر ما طبق اون توسعه بدیم میتونیم توی حافظه و پردازش صرفهجویی قابل توجهی انجام بدیم.
پترنها انواع مختلفی دارن. بعضیا برای ذخیره سازی داده استفاده میشن بعضیا برای روندهای همزمان و...
حالا فرض کنید داریم یک پروژه بزرگ رو توسعه میدیم و در طول کار دائم باید در کلاسهای مختلف تغییراتی رو ایجاد کنیم. همکارانی هم داریم که همزمان در حال توسعه هستن. هماهنگی این بین ممکنه خیلی دشوار بشه.
شاید همکار شما بر اساس سلیقه یا هر دلیلی دوست داشته باشه به شکل خاصی کد بزنه و شما شکل دیگه. از طرفی هر روش هم مزایا و معایبی داشته باشه.
برای همین پترنهایی بوجود اومده که روند و شکل توسعه رو هدف قرار داده. و اعضای تیم براساس پروژه تصمیم میگیرن از چه پترنی استفاده کنن. این الگوها هرکودوم مزایا و معایبی داره ولی بعد از اینکه تصمیم گرفته شد چه الگویی برای توسعه این پروژه خوبه تمام اعضا بر اساس اون کد میزنن و این باعث هماهنگی میشه.
البته هماهنگی کمترین فایده دیزاینپترنها برای توسعهست ولی شاید اولین فایده باشه. ولی بررسی فواید بیشتر باید هر پترن رو جدا بررسی کرد.
حالا بین این پترنها مدل MVC یک مدل شناخته شده و رایج هست که توی انواع پلتفرمها استفاده میشه.
MVC مخفف سه کلمه model - view - controller هست که خیلی خلاصه توضیح میدم.
model: ساختارهای پروژه رو در برداره. هر کلاس همراه با تمام متغیرها و constructor و... بخشی از مدل هستن.
view: میشه گفت شامل UI پروژهست. البته توی مدل MVC کار view بیشتر از فقط UI بودنه و از logic هم برخورداره ولی به دلیلی که اینجا ذکر کردم ما view رو فقط UI در نظر میگیرم. وقتی این کارو کنیم مدل تبدیل به MVP میشه. اما چون presenter نامانوستر از controller هست من از همون MVCC استفاده میکنم.
controller: ارتباط دهنده view و model هست. و logic برنامه رو شامل میشه. به عبارتی جریان اطلاعات داخل مدل رو کنترل میکنه و همچنین با تغییر مدل، ویو رو آپدیت میکنه.
دوستان به نظرم بهترین راه برای رسیدن به یک روش واحد توسعه گروهی هست برای همین من یک پروژه بر اساس آموختههام درست کردم و توی github قرار دادم. این پروژه بر اساس مدل MVP طراحی شده.
میدونم که این پروژه احتمالا خیلی ایراد داره. دلیل اینکه منتشر کردم هم این بود که با استفاده از آموختهها و با مشارکت هم پروژه رو به مرور تکمیل کنیم و ایرادات همدیگه رو رفع کنیم تا در نهایت به یک درک یکسان و درست از MVP و اساسا یک پترن برای توسعه برسیم.
توی این چند روزی که این تاپیک ایجاد شد متوجه شدم با صحبت کردن و تبادل نظر نمیشه به یک نتیجه واحد رسید، شاید اگر با هم کد بزنیم بهتر بتونیم نتیجه بگیریم.
برای مشارکت توی تکمیل این پروژه به لینک پروژه برید و اون رو fork کنید. اگر نمیدونید git چیست یا چطور میتونید در پروژه مشارکت کنید از اینجا شروع کنید. آموزشهای git آقای آقاجانی رو ببینید تا ایده اولیه دستتون بیاد. البته با خودِ اندروید استودیو و بدون کراکن هم میتونید تو پروژه مشارکت کنید. کافیه این آموزشها رو ببینید تا همهه چیز دستتون بیاد.
به خود کد بپردازیم.
تا الان چی کار کردم؟
بخش اول: ظاهر کد
اپلیکیشن 5 تا پکیج اصلی داره که تک تک توضیحشون میدم:
1. api: کلاسهای مربوط به api رتروفیت رو اینجا قرار دادم. بعد از مطالعه مقالات زیاد توی این چند روز به نظرم بهتر اومد کلاسهای apiها رو جدا از presenter نگهداریم.
2. model: همون مدلی هست که توی MVC و MVP و MVVM داریم. تنها ویژگیای که داره اینه که توش برای ساختمان دادههایی که مربوط به api هستن یک فولدر جدا در نظر گرفتم که به مرتب شدن کد کمک میکنه. همچنین توی فولدر api هم responseهای رتروفیت رو از بقیه زیر ساختارها جدا کردم. دلیل این کار تجربه شخصی بود که توی پروژههای بزرگ که ارتباطات زیادی با سرور داره و مدلهای رتروفیتی زیادی استفاده میکنیم پیدا کردن responseها شاید یکمی سخت بشه. برای همین جدا میکنم.
3. presenter: پرزنتر در مدل mvp رو اینجا قرار دادم. اطلاعات بیشتر راجع به اینکه presenter چیه -> اینجا.
داخل پکیج هم اینترفیسها رو از کدهای پیادهسازی جدا کردم. هدفم صرفا تمیزتر شدن کد بود.
4. utils: تمام کلاسهای مفید مثل چک کننده اینترنت، هندل کننده پرمیشن و... اینجا قرار میگیره
5. view: اکتیویتیها و فرگمنتها و adapterها و هر چیزی که کار view رو انجام بده اینجا قرار میگیره. من برای اکتیویتی، فرگمنت، ادپتر و کاستوم ویو ها پکیج جدا در نظر میگیرم. باز هم به دلیل خوانایی بیشتر در پروژههای بزرگ
بخش api و utils و model فکر نمیکنم احتیاجی به توضیح داشته باشه. با یک نگاه ساده به کد متوجه خواهید شد. برای همین view رو توضیح میدم.
بخش دوم: View
هر view دو بخش داره. بخش اول یک interface هست که مشخص میکنه view چه متدهایی رو اجرا خواهد کرد. و بخش دوم پیادهسازی همین متدهاست.
این پروژه فقط یک اکتیویتی داره (MainActivity) که MainView رو پیاده میکنه. MainView اینترفیس مربوط به MainActivityـه.
این سوال حتما پیش میاد که چرا برای پیاده کردن متدهای داخل اکتیویتی از interface استفاده میکنیم؟ دلیلش اینه که بعدا توی presenter میخوایم این متدها رو صدا کنیم و نمیخوایم برای این فراخوانیها به سراغ اکتیویتی بریم. چون کلا فلسفه تمام این کارها اینه که منطق کاریمون رو از view جدا کنیم و اکتیویتی فقط و فقط وظیفه نمایش رو داشته باشه.
یکسری وظایف ناخودآگاه به عهده activity هست. مثلا گرفتن permissionهایی که در ابتدای برنامه نیاز داریم. منطق این کارها هم به presenter منتقل شد و فقط توی MainView متدهایی برای پاس دادن context و activity پیشبینی شده که presenter بتونه این کارو انجام بده.
بخش سوم: Presenter
presenter هم مثل view از دو بخش interface و implementation تشکیل میشه.
ارتباط بین view و presenter با یک instance از اینترفیس MainView (یا هر اینترفیسی از ویوی که لازمه) انجام میشه.
بخش چهارم: RxAndroid
من برای ارتباط با سرور از RxJava و برنامهنویسی reactive استفاده کردم. RxAndroid و RxJava از پترن Observer استفاده میکنن و به ما کمک میکنن که راحتتر بتونیم taskkهای مختلف رو از هم جدا کنیم.
من دوست داشتم کل پروژه رو براساس Rx بنویسم ولی متاسفانه هنوز دانشش رو ندارم. این یکی از مهمترین بخشهاییه که میتونید کمک کنید تا پروژه تکمیلتر بشه.
چطور مشارکت کنید؟
اگر قصد تمرین دارید (کسایی که میخوان یاد بگیرن)
- برای کلاسها و متدهای پروژه کامنت مناسب اضافه کنید.
- یک loading برای زمانی که روی get jokes کلیک میشه تا زمانی که جوکها آماده بشه طراحی کنید.
- در ابتدای برنامه دسترسی به اینترنت رو چک کنید و پیام مناسب نمایش دهید.
اگر قصد مشارکت دارید (کسایی که میخوان به توسعه کمک کنن)
- قطعا پروژه ایراداتی داره. رفع یا گزارش اونها بزرگترین کمک تو پیشرفتِ پروژهست.
- در حال حاضر Rx فقط برای خوندن اطلاعات از اینترنت استفاده شده. اضافه کردن Rx به هر بخشی از پروژه یکی از کارهاییه که باید انجام داد.
- Dependency Injection با استفاده از Dragger انجام نشده.
هرچیزی که دانشش رو دارید و فکر میکنید توی پروژه دیده نشده رو اضافه کنید.
پینوشت1: من خیلی به مشارکت زیاد امیدوار نیستم. اگر وقت کافی ندارید همین که نگاهی به کدها بندازید و ایراداتی که به نظرتون میاد رو هم گوشزد کنید کمک خوبیه.
پینوشت2: حتما متوجه شدید که اسم پروژه یکمی نامربوطه دلیلش اینه که وقتی تصمیم گرفتم آموزش ویدیویی ضبط کنم پیش خودم گفتم با retrofit شروع کنم و بعد دیدم رتروفیت خیلی دمِ دستیه و خیلی آموزش هم زیاد داره برای همین تصمیم گرفتم رتروفیت رو با RxJava پیاده کنم. برای فهمیدن RxJava دیدم احتیاج هست که یکسری دیزاین پترن رو یاد بدم و در نهایت Rx بدون یک پترن خوب مثل MVC، MVP یا MVVM کاربردی نداره و عملا نمیشه از مزایاش استفاده کرد و خلاصه این شد که به اینجا رسیدم.
سلام خدمت همه دوستان و اساتید ... من مدتی که سعی دارم با mvp کد هام رو پیاده سازی کنم .... چن تا مشکل دارم ممنون میشم اگه کمکم کنید ..
1. 4 تا interface که تعریف میشه چه متد هایی باید الزاما داشته باشه .... این کد ها رو ببینید (interface MVP_Main ).... دارم از این لینک می خونم ....
http://smartlab.ir/%D8%A2%D9%85%D9%88%D8%B2%D8%B4-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF-%D9%85%D8%B9%D9%85%D8%A7%D8%B1%DB%8C-mvp-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF/
اگه از دوستان هم کسی مثالی ساده تر داشت ممنون میشم تو اشتراک بزاره ......
بالاخره یه کمی سرم خلوت شد و فرصت کردم یک پروژه کامل رو بر اساس MVP پیادهسازی کنم. اغلب روشهای پیادهسازی مختلف برای پترن mvp رو که تو اینترنت پیدا کردم رو بررسی کردم (از جمله روش قبلی خودم که همینجا صحبتشو کردیم) و به نظرم این شیوهای که الان معرفی میکنم خیلی بهتر از روشهای دیگهست.
سورس پروژه پر از کامنته و فکر میکنم واضح باشه که چی کار میکنه. میتونید اینجا سورس رو مشاهده کنید.
همچنین یک آموزش هم برای کد نوشتم که کلاسهای مختلف و نحوه ارتباطشون رو توضیح میده. میتونید آموزش رو اینجا مشاهده کنید.
مورد مهم در مورد این پروژه اینه که از هیچ کتابخونهای استفاده نشده و به طور کامل با استفاده از امکانات اندروید نوشته شده. یک نسخه دیگه از همین پروژه note رو هم آماده کردم که مشابه همین هست و فقط اینکه از تمام کتابخونههایی که این روزها trend شدن استفاده کرده.
لینک پروژه دوم همراه با آموزشش رو هم به زودی به همین پاسخ اضافه میکنم.
پاسخگویی و مشاهده پاسخ های این سوال تنها برای اعضای ویژه سایت امکان پذیر است .
چنانچه تمایل دارید به همه بخش ها دسترسی داشته باشید میتوانید از این بخش لایسنس این آموزش را خریداری نمایید .
MVP
بیشتر از باقی معماری ها مطرح هست، یعنی بیشتر محتواهای تولید شده ای که من دیدم پیرامون این معماری بوده، خود گوگل هم یه مخزن با مثال های مختلف بر اساس چند تا معماری داره لینک خودم فعلا باDagger2
وRxJava
سروکله میزنم تا بعد با MVP
شروع کنم. (7 سال پیش)