اگه براتون سواله که چرا باید از الگوهای طراحی استفاده کنیم بهتون پیشنهاد میکنم ابتدا ی پستی که در مورد الگوهای طراحی توضیح دادم رو بخونید بعدش این پست رو مطالعه کنید.
با توجه به صحبت های پست الگوهای طراحی ابتدا باید ببینیم که چه مشکل و مساله ای در دنیای برنامه نویسی به وجود اومده که الگو طراحی Repository برای حل اون مساله اختراع شده.
فرض کنید ما یک برنامه سمت سرور داریم که قرار است روی یک سری دیتا پردازشی انجام بدهد و خروجی را در یک فایل ذخیره کنه. دیتای مورد نیاز برنامه میتونه داخل همون سروری باشه که برنامه ما داخلش اجرا میشه یا میتونه به صورت محلی داخل خود برنامه ذخیره شده باشه یا میتونه داخل یک فایل نوشته شده باشه و برنامه ما باید دیتای خودش رو از اون فایل بره بخونه یا میتونه دیتا رو از یک سرور خارجی دیگه به وسیله اینترنت بگیره. همون جور که میبینیم اماده کردن دیتا برای برنامه ما میتونه از روش های مختلفی صورت بگیره در صورتی که برنامه ما اهمیتی براش نداره که این دیتا از کجا و به چه شکلی به دستش میرسه. در واقع مساله اصلی اینه که برنامه ما دوست داره یک برنامه ی جداگانه ای باشه که دیتا رو به دستش برسونه تا بتونه پردازش لازم رو روی اون دیتا انجام بده و تمرکزی رو این مساله نداشته باشد که دیتا از کجا قراره به دست ما برسه. همچنین برای به دست اوردن دیتا ما باید تحت پروتکل خاصی که اون دیتا ذخیره شده صحبت کنیم. یعنی فرض کنید دیتای ما روی یک فایل با فرمت خاص و به صورتی محلی داخل سرور ذخیره شده. برای استخراج داده ها باید بدونیم که فرمت خاص به چه شکلی هست و درگیر پیچیدگی مربوط به ان فرمت خاص بشیم. حالا ممکنه بعد از یک مدت برنامه ما نیاز داشته باشه یک سری فرمت خاص دیگه ای رو هم بتونه از روی فایل بخونه. یا مثلا فرض کنید برای ارتباط به یک سرور خارجی که بخواهیم دیتا بگیریم از لایبراری های مختلف برای ارتباط به اون سرور استفاده کنیم که مسایل مربوط به خودشون رو دارند. در واقع برای برنامه ما مهم نیست که دیتا به چه شکلی ذخیره شده و قراره به دست ما برسه همانطور که مهم نیست دیتا کجا ذخیره شده باشه. برنامه ما فقط میخاد دیتا بدستش برسه تا پردازش های لازم رو انجام بده.
به طور خلاصه برنامه ما نیاز نداره بدونه که دیتا از کجا و به چه شکلی قراره به دستش برسه.
یک مثال دیگه میتونه اپلیکیشن های موبایل باشه. فرض کنید در اپلیکیشن موبایل ما می خواهیم یک سری داده رو به کاربر نمایش دهیم ولی ممکنه این داده ها رو از resource های مختلفی ( سمت سرور یا از دیتابیس خود موبایل و یا یک داده ای باشه که قبلا از سرور گرفتیم و اون رو ذخیره داریم (Cache) ) بگیریم همچنین ممکنه برای ارتباط با سرور از لایبراری های مختلفی استفاده کنیم ( مانند Volley یا Retrofit).
در اصل برنامه ما از دو قسمت کلی تشکیل شده یکی نحوه گرفتن داده ها و یکی دیگه نحوه نمایش داده ها هست. برای اینکه بتونیم این دو قسمت رو از هم جدا کنیم و سعی کنیم پیاده سازی و پیچیدگی های مربوط به هر قسمت تاثیری روی قسمت دیگه نذاره از الگو طراحی Repository استفاده میکنیم.
به طور خلاصه میتونیم بگیم بهتره پیچیدگی های اینکه دیتا قراره از کجا و به چه شکلی به برنامه ما برسه رو از قسمت های دیگه اپلیکیشن جدا کنیم تا بتونیم راحت تر این موضوع رو مدیریت کنیم.
حال برای حل کردن مساله ( که همان الگو طراحی Repository می باشد) ما یک کلاس ( یا برنامه) طراحی میکنیم که وظیفه اصلی این کلاس اماده کردن دیتا می باشد. یعنی پیچیدگی های مربوط به فراهم کردن دیتا رو به این کلاس میسپریم و ما صرفا متد های این کلاس رو صدا میزنیم و کار نداریم که داده ی مورد نیاز ما از کجا ( سرور محلی - سرور خارجی - فایل محلی ...) و به چه شکلی ( به وسیله چه لایبراری) به دست ما میرسه.
در ادامه سعی میکنم این الگو طراحی را در غالب یک مثال توضیح بدم. میتونید این کد رو از github دانلود کنید.
مثالی که زدم خیلی خیلی ساده هست و از چند خط کد بیشتر تشکیل نشده. بیشتر سعی کردم مفهوم رو برسونم به جای اینکه درگیر پیچیدگی های مربوط به پیاده سازی دیتابیس یا ارتباط با سرور بشم.
در این قسمت برنامه ما از الگو طراحی Repository استفاده نکرده. برای دیدن کد های این قسمت داخل github بر روی تگ wo-repository کلیک کنید تا کدهای مربوط به این قسمت رو بتونید ببینید.
این تگ مخفف without repository هستش.
داخل عکس زیر نشون دادم که به چه صورتی باید اینکارو انجام بدید.
برای این مثال ما دوتا Resource برای به دست اوردن دیتا داریم. یکی دیتابیس یکی دیگه هم سرور.
این دوتا کلاس در برنامه های اصلی کارشون ارتباط با دیتابیس و یا سرور خارجی برای بازیابی اطلاعات هست ولی چون من نمیخاستم درگیر پیاده سازی های این دو کلاس بشم داده هارو به صورت محلی از داخل متود همون کلاس ها بازیابی کردم.
کلاس دیتابیس اطلاعات یک یوزر را در غالب string برمیگرداند.
کلاس سرور هم اطلاعات یک یوزر را در غالب byte[] برمیگرداند.
با این دوتا کلاس و متود صرفا میخواستم نشون بدم که ممکنه دیتا از جاهای (Resources) مختلف و به شکل های مختلف برای برنامه اصلی ما اماده بشه.
حالا برای اینکه از این دیتا ها داخل برنامه اصلی (Main.java) استفاده کنیم باید از هرکدام از این کلاس ها یک نمونه بسازیم و به وسیله دو تابعی که دارن داده ها را بازیابی کنیم.
مشکل اصلی برنامه ساده بالا اینه که برنامه اصلی (Main) ما نیاز داره بدونه اطلاعات هر یوزر از کجا ( یکی از یوزر ها داخل دیتابیس ذخیره شده و یکی دیگه از سرور اطلاعاتش میاد) و به چه شکلی (دیتابیس اطلاعات یوزر رو به شکل string برمیگرداند و سرور به شکل byte[]) بازیابی میشه.
حالا میخایم به کمک الگو طراحی Repository این مسایل پیش اومده رو برطرف کنیم.
برای این قسمت داخل github بر روی تگ w-repository کلیک کنید. این تگ مخفف with repository هستش.
برای حل کردن این مشکل یک کلاس به اسم RepositoryPattern.java درست میکنیم که وظیفه این کلاس مخفی کردن پیچیدگی های مربوط به بازیابی اطلاعات از برنامه اصلی میباشد.
همونطور که میبینیم این کلاس دوتا متود داره که اطلاعات مربوط به یوزر ۱ و یوزر ۲ را برای ما بازیابی میکند.
حال برنامه اصلی ما (Main) فقط کافیه از این دوتا متود کلاس RepositoryPattern استفاده کند بدون اینکه درگیر پیچیدگی های (از کجا و به چه شکلی) بازیابی اطلاعات بشود.