چالش RxJavaیی - یافتن شهرهای هر استان

بهترین راه یادگیری RxJava بعد از اینکه مفاهیم اولیه‌اش رو خوندید، حل مسئله‌های متفاوت با اون هست. اینکار باعث میشه به مرور تسلطتون روی RxJava و اپراتورهاش زیادتر بشه. امروز یه مسئله‌ای رو با هم بررسی میکنیم که تاحالا چند نفری در موردش ازم سوال پرسیدن. سه تا نکته رو فقط در نظر داشته باشید.

  • شاید بدون RxJava بشه این مسئله رو راحت‌تر حل کرد ولی اینجا هدفمون RxJava هست.
  • احتمال داره از چند روش بشه این مسئله‌ رو حل کرد، اصراری نیست که فقط راه‌حل من درسته.
  • برای اینکه کد تمیزتر باشه کاتلین استفاده کردم ولی خب میشه همینو با جاوا پیاده کرد.

خب مقدمه دیگه بسه، بریم ببینیم سوال یا مسئلمون چیه.

تعریف مسئله

دو تا کلاس City (شهر) و Province (استان) بصورت زیر داریم، از اون دو طرف هم دو تا متد داریم که یکیشون لیست استان‌ها و اون یکی لیست شهرهای یه استان رو از اینترنت بهمون میدن. توی برناممون نیاز داریم که لیست استان‌هارو رو با شهرهاشون از اینترنت بگیریم. چطوری میشه اینکارو با یه زنجیره RxJava انجام داد؟؟؟ (راهنمایی: میتونید به کلاس Province فیلد اضافه کنید)

https://gist.github.com/abbas-oveissi/25f0922846386f13a831e7f39fd573cf

حتما سعی کنید قبل اینکه کد راه‌حل رو بخونید، تلاش کنید تا خودتون پیاده‌سازیش کنید.

راه‌حل (هشدار اسپویل)

اگر با کد راحت‌تر هستید، این توضیحات رو نیاز نیست بخونید و بجاش مستقیم نمونه کد رو اینجا یا در آخر مقاله بررسی کنید. در ضمن توی این توضیحات فرض کردم که شما با RxJava و اپراتورهایی مثل flatmap و map و ... آشنایی دارید. پس اگر باهاشون آشنا نیستید، بهتره قبلش توی گوگل یه جستجویی در موردشون بکنید.

خب اولین کار برای حل مسئله اینه که لیست استان‌هایی که از متد getProvinces میگیریم رو تبدیل به دونه‌های Province بکنیم. اینکار رو میشه با Observable.from انجام داد. فقط چون خروجی این اپراتور از نوع observable هست، باید از flatmap استفاده کرد.

حالا در ادامه باید لیست شهرهای این استان‌هارو تک تک بگیریم. اینجا هم باید از flatmap استفاده کنیم ولی یه نکته داره. بذارید با این نکته رو با یه مثال توضیح بدم. توی بخش اول با flatmap لیست Province رو تبدیل به دونه‌های Province کردیم. اینجوری:

List<Province> ========FlatMap==========> Province

الان اگر به همون مدل از flatmap استفاده کنیم، اینجوری میشه:

Province ========FlatMap==========> List<City>

توی این حالت درسته لیست شهرهارو گرفتیم!! ولی خب دیگه به آبجکت Province دسترسی ندارید. در نتیجه بدردمون نمیخوره. چاره‌ی کار اینه که نگاهی به داکیومنت‌ اپراتور flatmap توی RxJava بندازیم. غیر از flatmapیی که بالاتر استفاده کردیم، یه flatmap دیگه هست که میشه دو ورودی بهش داد و این شکلی هست:

flatMap(final Func1<> collectior, final Func2<> resultSelector)

توضیح پارامتر اول collectior - این همون تابعی هست که داخلش بهمون یه Province میده و ما خروجی متد getCityByProvinceId که یه observable هست رو return میکنیم.

توضیح پارامتر دوم resultSelector - داخل این تابع اصل کارو انجام میدیم. داخلش بهمون یه آبجکت Province و نتیجه‌ی اون Observable که توی collectior براش return کرده بودیم رو میده. در نتیجه تنها کاری که باید بکنیم اینه یه فیلد به Province اضافه کنیم و این لیست رو بهش ست کنیم.

در آخر زنجیره‌مون هم از toList استفاده میکنیم تا دوباره دونه‌های Province رو یه لیست بکنه و بهمون تحویل بده. نمونه کد راه‌حل رو میتونید در ادامه مشاهده کنید.

https://gist.github.com/abbas-oveissi/170036ed900e5d148c113038669bc2ce

اگر شمام راه‌حل بهتری به ذهنتون میرسه توی بخش نظرات لینک gistشو بفرستید.