‫Singleton پترن در JavaScript

Singleton پترنسلام امروز اومدم که واستون یک دیزاین پترن رو توضیح بدم که اسم این دیزاین پترن Singleton هستمنطق کلی این دیزاین پترن میگه که ما باید class هایی داشته باشیم که فقط یکبار ازشون یک شی ایجاد کنیم و از این به بعد از اون بتونیم از اون شی ایجاد شده یکسره استفاده کنیم و دیگه شی جدیدی از کلاس نسازیم.حالا که منطق کلیش رو فهمیدیم بریم که با یک مثال قشنگ درک کنیمش ( اگه منطق کلیش رو هم نفهمیدید مشکلی نیست مثال رو ببینید کاملا میفهمید منظورم چیه :)) )اجزای کد ما :یک متغیر counter که توش مقدار شمارنده مون رو ذخیره میکنیم یک متدgetInstanceکه class ای که داریم رو return میکنهیک متد‫getCountکه مقدار فعلی متغیر counter رو return میکنهیک متد increment که مقدار متغیرcounterرو افزایش میدهیک متد decrement که مقدار متغیر counter رو کاهش میدهکلاس Counter ماحتما براتون این سوال پیش میاد که خوب این که یک کلاس سادست! بله کاملا دارید درست میگید این کلاس ما هنوز معیار های دیزاین پترن Singleton رو نداره! چرا معیارش رو نداره؟ الان توضیح میدم :)از یک کلاس Singleton فقط و فقط باید بشه یک شی ساخت و سری های بعدی باید از همون شی استفاده کرد اما از این کلاس ما میشه تا دلمون میخواد شی بسازیم :))Counter ساختن شی های مختلف از کلاسشاید بپرسید اون console.log ته کد چیه که با هم مقایسشون کردی؟ نکته اینه که وقتی کلاسمون Singleton باشه خروجی های متد getInstance اش با هم برابرند چون به یک کلاس اشاره میکنند اما اینجا چون هنوز کلاسمون Singleton نیست مقدارهاشون برابر نیستندCounter درست شدن دو شی مختلف از کلاسخوب حالا چطوری اینو بیاییم Singleton کنیمش؟رسیدیم به جای قشنگش :) بهترین راه برای اینکه مطمئن بشیم که فقط و فقط یک شی از این کلاسمون درست میشه اینه که یک متغیر بسازیم به اسم ‫instance و توی متد constructor کلاس Counter مون برای اولین باری که شی میخواد ساخته بشه کلاس رو تو متغیر instance بریزیم و در سری های بعدی ایجاد شدن شی مقدار متغیر instance رو چک کنیم و اگه مقدار متغیر خالی نبود ارور بدیم و بگیم فقط یکبار میشه از این کلاس شی ساختتوضیحش سخت بود و متوجه نشدید؟ بریم که یک مثال بزنم تا قشنگ درکش کنید :)کلاس Counter ما که singleton شدهو تماممممم :)) بلاخره تونستیم Singleton اش کنیمالان اگه دوبار از کلاسمان شی بسازیم برنامه ارور میدهحالا بیاییم این کلاسمون رو بریزیم تو یه فایل به اسم از فایل counter.js و بعد export کنیمش اما یه نکته ریزی رو باید اینجا رعایت کنیم که شی ساخته شده رو بریزیم داخل Object.freeze که مقداری از آبجکتی که داریم قابل تغییر نباشه و به نوعی آبجکتمون یخ بزنه :))) آبجکتی که داریم رو فریز کردیمش :)حالا بیاییم یه برنامه خیلی ساده با این پترن بسازیم که ببینیم چه شکلی میشه برناممون‫فایل counter.js که توی خودش کلاس Counter رو داره و در نهایت فریز شده اون رو export کردیمفایل index.js که توی خودش ایمپورت میکنه فایل redButton.js و فایل blueButton.js روفایل redButton.js که توی خودش import کرده فایل counter.js رو و یک button داره که رنگش قرمزه و روی اون یک event کلیک ست شده که متدincrement رو صدا میزنه و بعدش متد getCount رو صدا میزنه و مقدار برگشتی اون رو console.log میکنه‫فایلblueButton.js دقیقا همان کار فایل redButton.js رو میکنه ولی رنگش آبیه :))) (عجب تفاوت بزرگی)نکته ای که اینجا باید خیلی حواسمون باشه اینه که هر دو دکمه redButton و blueButton از یک instance استفاده میکنن که از counter.jsاومدهطوری که button هامون دارن از کلاس Counter استفاده میکننوقتی ما متد ‫increment رو در زمان کلیک redButton یا blueButton صدا میزنیم مقدار متغیر counter تو هر دوتا فایل فرق میکنه چون از این کلاس یک شی مشترک ساخته بودیماما استفاده از هر چیزی یه سری معایب هم داره که باید اون هارو هم دونست و بعد از اون چیز استفاده کرد پس بریم تا ببینیم معایب این کار چیهنیازی به class نداریم !یکی از خوبی هایی که ما توی این پترن داریم اینه که این پترن باعث میشه که تو استفاده از رممون صرفه جویی داشته باشیم چون دیگه هی لازم نیست شی های مختلف از یک کلاس بسازیم. لابد الان میگید که خوب این که همش فایده بود که ضررش کو؟. الان میگم ضررش کجاست :تو زبون های دیگه ای مثل Java و ++‫c این امکان وجود نداره که به صورت مستقیم ما یک آبجکت بسازیم و ازش استفاده کنیم اما توی js این امکان وجود داره و ما میتونیم خیلی کدمون رو ساده تر و راحت تر بنویسیمش بدون داشتن متغیر instance الان حتما مثل خودم هیجان زده اید که یعنی چطوری میشه اینکارو کرد؟ بریم که مثال رو ببینیم با هم:اجزای کد :متغیر count که توش مقدار شمارنده مون رو ذخیره میکنیم متدincrement که توش مقدار متغیر count رو یک واحد اضافه میکنیممتد decrement که توش مقدار متغیر count رو یکم واحد کم میکنیممتد getCount که توش مقدار متغیر count رو ریترن میکنیمنوشتن یک آبجکت ساده که دقیقا چیزی که ما میخواییم رو داره مشکل داشتن تو تست نویسیاگه تو برنامتون تست داشته باشید و بخوایید این class رو واسش تست بنویسید باید حواستون باشه که بخاطر تعداد صدا زدن متد های مختلف یا بهم خوردن ترتیب صدا زدنشون مقدار تست های پایینی هم ممکنه چیزی که میخوایید نباشه و این شکلی میشه که همه تست هاتون fail میشه در صورتی که class تون داره درست کار میکنه :))) نمونه یک تست نوشته شدهمعلوم نبودن مقدار فعلیاز اونجایی که این مقدار ما داره تو کل برناممون استفاده میشه ممکنه ما از این کلاس توی جایی استفاده کنیم و انتظار داشته باشیم که مقدارش مثلا 0 باشه اما یهو میبینیم چون تو یه کامپوننت دیگه مقدارش زیاد شده مقدار اولیه اش 4 هست و باعث میشه باگ های عجیب و غریب تو برنامه درست بشهجمع بندی کلی :در کل ایده داشتن متغیر هایی بصورت گلوبال ایده خوبی نیست چون میتونه اتفاقات غیر منتظره ای رو تو برنامه ما ایجاد بکنه مخصوصا تو es6 و این داستانا که let و const اومدن باعث شدن که دولپر ها تا حد ممکن متغیر هایی رو داشته باشن تو برنامه هاشون که پایبند یک scope باشه. اما بازم با سیستم ماژول بندی js میشه تا حدی از این اتفاقات غیر منتظره جلوگیری کرد.مهم ترین چیز تو استفاده از این پترن ترتیبیه که دارید از این کلاس ها میکنید باید سعی کنید تا حد ممکن بصورت تصادفی داده هارو عوض نکنید و اون هارو زمانی استفاده کنید که هنوز داده ای برای مصرف وجود نداره (منظورم موقع ایجاد شدن یک کامپوننت و یا اتصال و گرفتن دیتا از دیتابیس و ایناست)تو React ما اغلب به جای استفاده از کلاس های Singleton از ابزارهای State management مثل Redux یا React Context استفاده میکنیم. اگرچه گلوبال بودن اونها ممکنه شبیه به کلاس های Singleton باشه اما این ابزارها به جای حالت قابل تغییر دادن دیتا تو Singleton فقط امکان خوندن دیتا ها را ارائه میدن مثلا وقتی که داریم از Redux استفاده میکنیم تنها فانکشن های reducer که هیچ side effect ای ندارن استیت رو آپدیت میکنن.ممنون که وقتتون رو گذاشتید و این مقاله رو خوندید من این مقاله رو این شکلی نوشتم که اول این سایت رو خوندم و هرچی که فهمیدم رو براتون نوشتم و قراره مقاله های دیگه این وبسایت رو هم همین کار بکنم و واستون بزارمشون.اگر اشکالی دیدید یا انتقادی داشتید ازم ممنون میشم تو کامنت ها بگیدش