Siavash Aghazadeh
Siavash Aghazadeh
خواندن ۵ دقیقه·۱۷ ساعت پیش

📐 React Design Pattern's (part-2)

بریم سراغ پارت دومِ Design Pattern های توی React. یه مشکل اساسی که من داشتم این بود که به صورت مفهومی دوتا از پترن های مهم Factory و Adapter رو درست متوجه نمیشدم. که اینجا مفهومی و با مثال بهشون پرداختم تا درکشون راحت تر بشه. و اینکه به یکی از پر استفاده ترین ها یعنی Provider Pattern میپردازیم.
❗️ فقط نکته اینکه مثال هایی که میزنم صرفا روش درستی برای هندل کردن اون مثال توی دنیای واقعی نیست، فقط برای درک اون پترن مثال هارو میزنم.

  • Factory Pattern
  • Adapter Pattern
  • Provider Pattern

1- Factory Pattern

فرض کن یه اپلیکیشن داری که برای مدیریت پرداخت‌ها ساخته شده. تو نسخه اول فقط پرداخت با کارت بانکی پشتیبانی میشه. همه کدت توی کامپوننتی به اسم BankCardPayment نوشته شده.
بعد از مدتی، کاربران میگن:

  • پرداخت با PayPal رو هم اضافه کن!
  • پرداخت با کریپتو چی؟

حالا اگه بخوای هر بار یه نوع پرداخت جدید اضافه کنی، باید کلی کد رو تغییر بدی و شرط بذاری ؛ مثلاً

if (type === 'PayPal') یا if (type === 'Crypto')

این باعث میشه کدت به مرور زمان شلوغ، پیچیده، و سخت برای نگهداری بشه.

🎯 حالا ببینیم Factory Pattern چجوری این مشکل رو حل میکنه !
با استفاده از این پترن، به جای اینکه خودت مستقیم تصمیم بگیری کدوم کلاس یا کامپوننت رو بسازی یا استفاده کنی، این تصمیم رو به یه کارخونه (Factory) واگذار میکنی. یعنی یه تابع یا آبجکت داری که بر اساس ورودی‌ها (مثل نوع، پارامترها یا شرایط)، به صورت داینامیک چیزی که لازمه رو می‌سازه یا برمی‌گردونه. این کار باعث میشه کدت تمیزتر، قابل گسترش‌تر و از نظر نگهداری راحت‌تر بشه، چون همه تصمیم‌گیری‌ها متمرکز و مستقل از بقیه کده.
چطور با Factory Pattern حلش کنیم؟
به جای اینکه توی یه فایل شرط‌های مختلف بذاری، میای یه ساختار انعطاف‌پذیر درست می‌کنی که بر اساس نوع پرداخت، کامپوننت مناسب رو برگردونه.

در نتیجه Factory یه شاه‌کلیده برای ساخت کدهای تمیز و انعطاف‌پذیره. این الگو نه‌تنها بهت اجازه میده کامپوننت‌های مختلف رو بدون نیاز به شرط‌های پیچیده و شلوغ مدیریت کنی، بلکه روند اضافه کردن قابلیت‌های جدید رو هم آسون می‌کنه. با استفاده از Factory، کدت از یه سیستم بهم‌ریخته به یه معماری مرتب و قابل نگهداری تبدیل میشه.


2- Adapter Pattern

فرض کنید شما در حال کار با یک سیستم هستید که از دو API مختلف برای دریافت اطلاعات کاربرا استفاده می‌کنه. یکی از این‌ها API قدیمی شرکت شماس و اون یکی یک سرویس جدید که اخیراً اضافه شده. هر کدوم از این‌ها داده‌ها رو با ساختار متفاوتی برمی‌گردونند. مشکل اینه که کل اپلیکیشن شما داره با یک ساختار ثابت با ریسپانس این سرویس ها کار میکنه.
اگه قرار باشه از سرویس جدید استفاده کنید باید دوتا مورد رو در نظر بگیرید:

  • هر جای اپلیکیشن از ساختار قدیمی استفاده کردین و آپدیت کنید و به ساختار جدید تغییر بدین
  • دیگه نمیتونید از سرویس قدیمیه استفاده کنید.

🎯 خب حالا Adapter Pattern چجوری مشکل و حل میکنه !؟
این الگو با ایجاد یک لایه میانی به نام "آداپتر" عمل می‌کنه که مثل یک مترجم بین API‌های مختلف و کامپوننت‌های ما عمل می‌کنه. تصور کنید شما یک شارژر موبایل دارید که پریز برق رو به موبایلتون متصل می‌کنه. آداپتر هم دقیقاً همین کار رو انجام میده. برای هر API، یک آداپتر جداگانه می‌سازیم که می‌دونه داده‌های اون API رو چطور به فرمت استاندارد ما تبدیل کنه. مثلاً وقتی API قدیمی از user_id استفاده می‌کنه و API جدید از id، آداپتر مربوطه می‌دونه که باید این فیلدها رو به چه شکلی تبدیل کنه تا کامپوننت‌های ما بتونن باهاشون کار کنن. به این ترتیب، کامپوننت‌های ما فقط با یک ساختار داده استاندارد کار می‌کنن و نیازی نیست برای هر API تغییر کنن👌
بریم که کدشو بزنیم

بیایم ببینیم که هر کدوم از سرویس ها ساختار ریسپانسشون به چه شکلی هستش :

تو مرحله اول میایم Adapter های هرکدوم از سرویس ها و interface رو مینویسیم :

برای راحتی کار میایم یه کاستوم هوک هم مینویسم که fetch کردن دیتا و Adapte کردن دیتا رو هندل کنیم:

بعد میریم سراغ کامپوننت نمایش userProfile و نحوه استفاده از اون کامپوننت :

نکته اخر اینکه این دیزاین پترن هدفش این نیست که بیایم و از سرویس ها قدیمی و جدید به این شکل استفاده کنیم، بلکه بیشتر هدفش توی فرانت اینه که از third party libraries ها بهتر بتونیم استفاده کنیم. مثلا ما داریم از یک input توی Ant Design استفاده میکنیم، بنا به دلایلی تصمیم میگیریم که لایبری رو تغییر بدیم به MUI. اینجا نباید بریم توی کل اپلیکیشن و کلی تغییرات بدیم، به جاش میایم از یک Adapter استفاده میکنیم. که واقعا کارو آسون میکنه✌️


3- Provider Pattern

یکی دیگه از پترن های React که تقریبا همیشه داریم ازش استفاده میکنیم، Provider Pattern هستش.
فرض کنید، اطلاعاتی مثل تم (Theme) یا کاربر لاگین شده باید بین چندین کامپوننت به اشتراک گذاشته بشه.

تاکید میکنم اینها روش درستی برای هدل کردن اینجور مثال ها نیستن، صرفا برای فهم این پترن ها همچین مثال هایی میزنم.

اگر بخواهیم این اطلاعات را از طریق Props Drilling (ارسال داده از طریق پراپ‌ها) مدیریت کنیم، کد بسیار پیچیده و نامرتب می‌شود. که باعث میشه وقتی تعداد کامپوننت‌ها زیاد بشه، مدیریت داده هم سخت‌تر بشه و نکته مهم تر اینکه هر تغییری تو ساختار داده باید تو تمامی کامپوننت‌های زنجیره اعمال بشه.
مثل این کد :

🎯 ببینیم Provider Pattern چجوری مشکل و حل میکنه !
در واقع این پترن یک پترن مدیریت استیت تو React هست که مشکل انتقال داده بین کامپوننت‌های عمیق رو حل می‌کنه. این پترن معمولاً با استفاده از Context API تو React پیاده‌سازی میشه.

خب بریم برای پیاده سازی :

  • اول یک context برای داده‌های مشترک می‌سازیم.
  • یک کامپوننت که نقش Provider را ایفا می‌کنه، می‌سازیم و داده‌ها را تو اون قرار میدیم.
  • قرار دادن Provider در بالاترین سطح (معمولا توی layout ها)
  • استفاده از Context تو کامپوننت‌ها.

❗️این نکته مهم و در نظر داشته باشین که؛ Provider Pattern بخشی از مفهوم State Management هستش، اما جایگزین کاملی برای اون نیست. خوده بحث State Management باید جداگونه بهش پرداخته بشه.

پارت دوم هم تموم شد، ممنون میشم شما هم نظرات خودتونو یا هر سوالی درباره هرکدوم از پترن ها دارین باهام به اشتراک بزارین. منتظر پارت بعدی باشین 🙏
امیدوارم مطالب مفید بوده باشه ✌️❤️

design patternreactfrontendweb developmentjavascript
Front-end Developer
شاید از این پست‌ها خوشتان بیاید