<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های پوریا سیفی</title>
        <link>https://virgool.io/feed/@PouriaSeyfi</link>
        <description></description>
        <language>fa</language>
        <pubDate>2026-04-15 06:48:46</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/79572/avatar/gKUeic.jpg?height=120&amp;width=120</url>
            <title>پوریا سیفی</title>
            <link>https://virgool.io/@PouriaSeyfi</link>
        </image>

                    <item>
                <title>Screaming Architecture</title>
                <link>https://virgool.io/@PouriaSeyfi/screaming-architecture-ny1oiq4osz0f</link>
                <description>آیا معماری نرم‌افزار شما &quot;فریاد میزنه&quot;؟ 📢😲وقتی به نقشه ی یک خونه نگاه میکنیم اولین المان هایی که توجه مارو جلب میکنن آشپزخونه، حیاط، اتاق خواب و این چیزاست. نقشه یه کتابخونه هم با محوطه، لابی، قفسه‌ها و سالن مطالعه همین حس رو داره. به عبارتی، نقشه یه ساختمونخودش داره داد می‌زنه که چیه!تو دنیای نرم‌افزار هم معماری سیستم باید هدف کسب‌وکار رو فریاد بزنه، نه اینکه توی انبوهی از ابزار و تکنولوژی گم بشه! وقتی کد یه پروژه رو می‌بینیم، باید سریع بفهمیم &quot;این سیستم چیکار می‌کنه&quot;، نه اینکه از چه فناوری‌هایی استفاده کرده🤕به نظر من این رویکرد میتونه یه معیار شفاف برای ساختار پروژه‌ ها باشه: فولدربندی بر اساس دامین یا فیچرها باشن، نه کنترلر و ریپازیتوری و چیزای تکنیکال. یکی دیگه از نشانه های معماری خوب اینه که اجازه بده انتخاب تکنولوژی های از قبیل دیتابیس و وب سرور و حتی فریم ورک رو به تعویق بندازیم و روی یوزکیس هامون تمرکز کنیم. طبعا اینکار منجر به تست پذیری بهتر معماری میشه.وقتی یونیت تست های ما مستقل از مکانیزم دلیوری، فریم ورک، دیتابیس و تکنولوژی های دیگه باشند، تغییر اون تکنولوژی و ابزار ها تاثیر زیادی بر منطق اصلی بیزینس ما نخواهد داشت.  یادمون باشه حتی تحت وب بودن یک پروژه صرفا یک مکانیزم دلیوری هست و هیچ ارتباطی با منطق بیزینسی ما نداره. اگر قرار باشه یک اپلیکیشن کنسول هم به پروژه اضافه کنیم، باید خیالمون راحت باشه که منطق بیزینسی ما قبلا تست شده و صرفا یک لایه دلیوری دیگه به پروژه اضافه کردیم.توسعه ی فریم ورک محور یا تاکید بیجا روی ابعاد تکنیکال مثل ابزار ها و پاردایم ها ( کنترلر و ریپازیتوری و...) یا حتی تاکید روی استایل معماری هایی مثل هگزاگونال (پورت و اداپتر و ...) و یا استفاده نادرست از دیزاین پترن ها هم میتونه باعث بشه معماری ما شفاف نباشه و فریاد نزنه :)این هم لینک مقاله اصلی https://blog.cleancoder.com/uncle-bob/2011/09/30/Screaming-Architecture.html</description>
                <category>پوریا سیفی</category>
                <author>پوریا سیفی</author>
                <pubDate>Fri, 04 Apr 2025 13:33:57 +0330</pubDate>
            </item>
                    <item>
                <title>دیزاین پترن Proxy به زبان ساده ?️‍♀️</title>
                <link>https://virgool.io/@PouriaSeyfi/%D9%94%D8%AF%DB%8C%D8%B2%D8%A7%DB%8C%D9%86-%D9%BE%D8%AA%D8%B1%D9%86-%D9%BE%D8%B1%D9%88%DA%A9%D8%B3%DB%8C-%D8%A8%D9%87-%D8%B2%D8%A8%D8%A7%D9%86-%D8%B3%D8%A7%D8%AF%D9%87-%EF%B8%8F%EF%B8%8F-n34rfsfmvcwh</link>
                <description>سلام امیدوارم که حالتون خوب باشه و از مسیری که توش قرار دارید لذت ببرید. امروز قراره در مورد Proxy Design Pattern که یک الگوی طراحی ساختاری (structural) هست  صحبت کنیم.متاسفانه واژه پراکسی برای ما ایرانیا انقدر آشنا هست که همه ما با تمام سلول هامون درکش کردیم  :)البته مفهموم پراکسی در Proxy Server و Proxy Design Pattern دو موضوع متفاوت هستن ولی هر دو شون یک ایده مشترک رو بیان میکنند. خب اول یه سوال خیلی ساده رو جواب بدیم ‌:  تو پراکسی هایی که همه ما مجبور به استفاده ازشون هستیم دقیقا چه اتفاقی داره میفته ؟ پراکسی در واقع یک واسطه ست که به جای ما عمل میکنه. مثلا به جای اینکه ما مستقیم به سرورهای تلگرام درخواست بدیم، به Proxy Server درخواست میدیم که اون نتیجه درخواست رو به ما برگردونه. ( میدونیم که لوکیشن پراکسی سرور ها در ایران نیست و در نتیجه تلگرام اونجا فیلتر نیست پس میتونن واسطه بین ما و تلگرام  باشند).در مورد الگوی Proxy هم تقریبا همین اتفاق میفته . پراکسی یک جایگزین یا نگهدارنده (place holder) برای یک شی دیگه ست تا ما بتونیم دسترسی به اون شی رو، کنترل و مدیریت کنیم. پس در تعریف این الگو هم پراکسی در واقع یک کلاس واسطه ست که قراره به جای  کلاس اصلی (subject) فراخوانی بشه و نماینده ای از اون باشه .در واقع هدف اصلی الگوی Proxy ایجاد یک سطح واسطه‌گر بین کد کلاینت و شی مورد نظر ماست . حالا هدف از انجا این کار چیه ؟ هدف اینه که قبل از اینکه درخواست‌ها (منظور از درخواست اینجا فراخوانی متد های شی مورد نظر هست) به شی برسند توی لایه پراکسی قابل رصد و  پردازش باشند. در این صورت میتونیم کنترل و مدیریت بهتری روی درخواست ها داشته باشیم یا حتی ویژگی های جدیدی به اون درخواست اضافه کنیم. بدون اینکه مجبور باشیم به کلاس اصلی دست بزنیم. خب اگر آماده هستید بریم سراغ یک مثال واقعی :  قراره که برای فایل های سیستم بتونیم یه سری عملیات خوندن و نوشتن داشته باشیم. کلاس زیر رو در نظر بگیرید : فرض کنیم بعد از یه مدت که با این کلاس کار کردیم و بدون مشکل هم همه چیز اجرا میشده حالا از ما خواسته شده که فقط افراد خاصی بتونند فایل ها رو بخونند و همچنین  بعد از عملیات های مختلف لاگ هم ثبت بشه و همچنین قابلیت کش شدن هم اضافه بشه! آیا شما تو این حالت وارد کلاس FileSystem میشید و با حرکات مختلف سامورایی کلاس اصلی رو قلع و قمع میکنید ؟ اساسا ویژگی های جدیدی که از ما خواسته شده وظیفه کلاس FileSystem  نیست (اصل یک سالید)این ویژگی های جدیدی که مطرح شده همون مدیریت و کنترل هایی هستند که قبل از درخواست به شی اصلی باید هندل بشوند (همون نیازی که پراکسی برطرف می کرد) پس راهکار استفاده از دیزاین پترن پروکسی هست :همونطور که تو کد بالا مشخصه بررسی کردن سطح دسترسی ها، لاگ گیری و کش کردن همگی تو لایه پراکسی داره مدیریت میشه  ?
$proxy = new FileSystemProxy(new FileSystem&#40;&#41;);
$handle = $proxy-&gt;openFile&#40;&#039;example.txt&#039;&#41;;
$data = $proxy-&gt;readFile&#40;$handle&#41;;الگوی پراکسی در چند حالت میتونه راهکار مناسبی ارائه بده : Remote Proxyدر صورتی که شی مورد نظر ما در یک سرویس خارجی (مثلا API خاص در یک سرور دیگه) وجود داره و ما نمیخوایم درگیر جزئیات این ارتباط بین برنامه خودمون (local) و سرور بشیم. چالش مدیریت و کنترل ارتباط بین لوکال و سرور میتونه در پراکسی هندل بشه .  Protection Proxyفرض کنیم برای گرفتن اطلاعات مختلف از یک شی باید سطح دسترسی های خاصی هم بررسی بشه در این صورت لایه پراکسی ما میتونه این وظیفه رو به عهده داشته باشه چون قطعا وظیفه اون شی قطعا این نیست که با یه سری شرط و شروط این دسترسی ها رو چک بکنه . بنابراین اینجا پراکسی نقشی از نگهبان رو ایفا میکنه. شبیه مثال فایل سیستم که در بالا مطرح شد.Virtual Proxyفرض کنیم کلاسی داریم که موقع ساخته شدن (در متد سازنده  خودش) هزینه زیادی رو به ما تحمیل میکنه (از نظر منابع یا زمان) ، از طرفی ممکنه ما ما در اون لحظه نیازی به ساخته شدن شی به صورت کامل نداشته باشیم. بنابراین خوبه که یه پراکسی این ساخته نشدن در لحظه ای که نیاز نداریم  (Lazy initialization) رو برای ما مدیریت کنه. Smart Proxy در این نوع پراکسی ما میتونیم ویژگی های جدید به ابجکت اضافه کنیم به عنوان مثال کش کردن یا لاگ گرفتن از ابجکت در فراخوانی های مختلف . یا حتی اینکه اگر کسی از اون ابجکت دیگه استفاده ای نمیکنه به صورت خودکار از حافظه پاک بشه. در واقع رفتار های رو وارد کلاس کردیم که شی مون هوشمندانه تر عمل کنه. و این عملکرد  هم داره در سطح پراکسی مدیریت میشه.  امیدوارم مطالبی که مطرح شد براتون مفید بوده باشه و ممنون از همراهی تون</description>
                <category>پوریا سیفی</category>
                <author>پوریا سیفی</author>
                <pubDate>Fri, 01 Sep 2023 15:46:38 +0330</pubDate>
            </item>
                    <item>
                <title>دیزاین پترن Bridge به زبان ساده ?</title>
                <link>https://virgool.io/@PouriaSeyfi/%D8%AF%DB%8C%D8%B2%D8%A7%DB%8C%D9%86-%D9%BE%D8%AA%D8%B1%D9%86-bridge-%D8%A8%D9%87-%D8%B2%D8%A8%D8%A7%D9%86-%D8%B3%D8%A7%D8%AF%D9%87-iyb8e6bxsmc2</link>
                <description>قبل از اینکه وارد توضیحات اصلی بشیم بیاید یه مسئله ساده رو حل کنیم. فرض کنید دو مجموعه ساده A و B داریم.A =  {x, y, z}
B =  {1, 2, 3}فک میکنید  ترکیبات  دوتایی ممکن، از اعضای این دو مجموعه چه تعداد هست؟  جواب خیلی ساده ست اما تو تصویر زیر بهتر متوجه میشیم :راه حل کلی این مسئله تو دنیای ریاضیات ضرب دکارتی هست که میشه ۹ حالت ممکن. اما چرا  مقاله رو با این مسئله شروع کردیم؟بیاید فرض کنیم هر کدوم از اعضای مجموعه هایی که مطرح شد یه کلاس باشند:مجموعه اشکال هندسی (کلاس مربع و کلاس دایره)مجموعه رنگ ها (کلاس آبی و قرمز )پس ما با یه سری کلاس در دو دسته بندی متفاوت سر و کار داریم ینی شکل ها و رنگ ها. خب حالا اگر بخوایم با این کلاس ها اشکال هندسی رنگی بسازیم. چند کلاس مجزا میتونیم برای هر شکل رنگی داشته باشیم :شبیه به همون ضرب دکارتی هست که میشه ۴ کلاس : خب تا اینجا همه چیز خیلی مرتبه ، حالا فرض کنیم یه شکل و رنگ جدید رو بخوایم داشته باشیم(مثلا یک مثلث و یک رنگ زرد) . اگر بخوایم طبق همین روند بالا پیش بریم تعداد کلاس هامون میشه ۹ عدد.پس اگر قرار باشه ما با به وجود اومدن رفتارهای مختلف، کلاس های جدیدی بسازیم حتما یه جای کار میلنگه... چون میبینیم که تعداد این کلاس ها داره خیلی زیاد میشه. در واقع بیشتر شدن رفتار های جدید، باعث میشه تعداد کلاس هایی که میتونیم بسازیم به صورت نمایی بالا بره !حالا به تصویر زیر دقت کنید :تو این نمودار میبینیم که کلاس هایی که  توی دسته بندی های متفاوتی قرار دارند (اشکال هندسی و رنگ) به این صورت از هم تفکیک شدند.  طبیعیه که ما قرار نیست به ازای هر ترکیبی از کلاس ها، یک کلاس جدید بسازیم. میتونیم با ترکیب (compose) کردن این کلاس ها تو کد هامون به همون خروجی که میخوایم برسیم :$red = new Red();
new Square($red);اون فلش قرمز (contains) در تصویر هم رو همین موضوع تاکید داره. درواقع این تصویر داره به ما میگه که هر شکل هندسی میتونه در خودش (متد سازنده ش) نیازمندی خودش به رنگ رو هندل بکنه .پس میبینیم که ما به جای  inheritance  از object composition استفاده کردیم. تو مقاله  Adapter Design Pattern هم به این موضوع اشاره کرده بودیم.خیلی خب تا اینجا یکی نگرانی های ما با این الگوی ساده برطرف شد. حالا بریم ببینیم دیزاین پترن Bridge  چی هست و کجا ها به کارمون میاد. تعریف اصلی دیزاین پترن این هست :Decouple an abstraction from its implementation so that the two can vary independently.ترجمه :  لایه abstraction از implementation جدا بشه که این دو بتونن مستقل از هم تغییر پیدا کنند.هیچ جوره نمیشه جمله رو هضم کرد واقعا ??? به نظر جمله خیلی آکادمیک هست و باعث شده از چیزی که واقعا هست پیچیده تر به نظر بیاد. طبق معمول بریم که مسئله رو با مثال واقعی درک کنیم :پیاده سازی ارسال اعلان (Notification) :فرض کنیم از ما خواسته شده که اپلیکیشن ما ارسال اعلان داشته باشه و  اعلان ها حالت دو عادی و فوری داشته باشند. با توجه به فوری یا عادی بودن اعلان انتهای پیام شامل متن خاصی میشه یا مثلا فوری باید سریع تر ارسال بشه و مطمئن شیم کاربر اونا رو تحویل گرفته و... خیلی ماهیت مثال مهم نیست.مسئله ای که الان مطرحه اینه که ما اساسا یک انتزاع به اسم Notification داریم که قراره رفتار فوری و عادی داشته باشه. از طرفی میدونیم که اعلان ها از طریق کانال های مختلفی قابل ارسال هستند. مثلا پیامک و ایمیل گزینه های خوبی هستند.خب اگر خوب دقت کنیم میبینیم که تو این مثال هم ما با دو مجموعه متفاوت از کلاس ها سر و کار داریم.اولین مجموعه :  عادی یا فوری اعلاندومین مجموعه : کانال ارسال اعلان (ایمیل یا پیامک)شبیه به همون مثال اشکال هندسی و رنگ ها شد که ابتدای مقاله صحبت کردیم :پیاده سازی کد ها :حالا  ما برای اینکه یه اعلان از نوع فوری و از طریق کانال پیامک ارسال کنیم به صورت زیر عمل میکنیم :$smsChannel = new SMSChannel();  
$urgentSMS = new UrgentNotification($smsChannel);
$urgentSMS-&gt;send(&amp;quotUrgent alert: Please take immediate action!&amp;quot);حالا فرض کنید شرایطی پیش میاد که ما باید یک کانال جدید (مثلا ارسال از طریق تلگرام) اضافه کنیم یا مثلا برای کانال پیامک مجبور باشیم تغییراتی در ساختار بدیم. آیا این اضافه شدن و یا تغییراتی که قرار به ما تحمیل بشه روی عادی بودن و فوری بودن اعلان ها تاثیری میذاره ؟ قطعا خیر.بیاید دوباره تعریفی که برای دیزاین پترن ارائه شد رو  مرور کنیم :Decouple an abstraction from its implementation.انتزاع (abstraction) ما تو این اپلیکیشن ارسال اعلان و فوری و عادی بودنش بود و پیاده سازی (implementation) ما کانال های پیامک و ایمیل. و ما موفق شدیم این دو لایه رو از هم تفکیک کنیم که تغییرات احتمالی رو هر کدوم، تاثیری بر اون یکی لایه نداشته باشه.حالا واقعا تفاوت Abstraction و Implementation چیه ؟به نظرم تا اینجای کار شرایط بسیار خوبی فراهم شده که واقعا به این سوال خیلی مهم پاسخ بدیم. تو این مثال خیلی شفاف میشه فهمید اساسا تفاوت این دو چی هست.ما میدونیم که Abstract کلاسی هست که میتونه بدنه داشته باشه و نمیشه ازش ابجکت ساخت ولی تو عمل چی ؟ واقعا کجا باید از Abstract استفاده کنیم و کجا باید به Interface ها فکر کنیم ؟خب برگردیم به مثالی که مطرح کرده بودیم . ما میتونیم پیاده سازی های متفاوتی برای یک انتزاع داشته باشیم. یعنی چی؟بیاید مثال رو ادامه بدیم تا ایده implement کردن برامون شفاف تر بشه :فرض کنیم تا اینجای کار ما اعلان رو برای یک سری افراد به صورت تکی ارسال میکردیم. حالا شرایطی پیش اومده که نیاز داریم یک اعلان برای گروهی از افراد ارسال بشه. مثلا افرادی که روز تولدشون هست یا افرادی که سفارشی تو سایت ما ثبت کردن و حالا میخوایم بهشون ناتیف بدیم که بیان و نظر خودشون در مورد سفارشی که دریافت کردن تو سایت وارد کنند و...اتفاقی که اینجا داره میفته اینه که انتزاع ما (Notification) یه پیاده سازی دیگه لازم داره که بتونیم دریافت کنندگان مختلف رو هندل کنیم. چون دریافت کنندگان یه مقدار منطقش پیچیده شده و قطعا وظیفه فوری و عادی بودن نیست که بدون دریافت کنندگان چه افرادی هستند. همینطور وظیفه کانال های پیامک و ایمیل هم نیست.پس ما نیاز به یک اینترفیس جدید داریم .حالا میتونیم پیاده سازی های متفاوتی از این اینترفیس داشته باشیم :حالا تو قدم آخر کافیه که  تو متد سازنده Notification، دریافت کنندگان مورد نظر خودمون هم پاس بدیم. بدون اینکه مجبور باشیم تغییر خاصی در باقی کلاس ها بدیم قابلیت های متفاوتی در سیستم ایجاد کنیم. اینطوری یه رفتار جدید رو به سیستم اضافه کردیم که مستقل از رفتار های دیگه عمل میکنه.باز هم میبینیم که حتی با ایجاد Implementation های جدید لایه های دیگه درگیر تغییرات نمیشن . اینکه ما دریافت کنندگان رو چطوری به دست بیاریم هیچ ربطی به فوری و عادی اعلان (Abstraction) بودن .بریم ببینیم کارهایی که تاحالا کردیم چقدر داره کمک میکنه اصول سالید رو رعایت کنیم :اصل اول (single responsibility)هر کلاسی که ایجاد میشه یک مسئولیت مشخص داره و نه بیشتر.اصل دوم (open closed) :با ایجاد کانال جدید اتفاقی برای کلاس های دیگه نمیفته.اصل چهارم (interface segregation) :اینترفیس دریافت کننده ها و کانال های اعلان ربطی به هم ندارند پس به صورت مستقل از هم عمل میکنند.اصل پنجم  (dependency inversion)ماژول های سطح بالا مثل RegularNotification و UrgentNotification به کلاس های سطح پایین مثل SMSChannel  وابسته نیستند بلکه  به مفاهیم انتزاعی (NotificationChannel) وابستگی دارند هستند.در آخر شاید براتون جالب باشه که چرا اسم این دیزاین پترن bridge یا پل هست. تو تصویر زیر خیلی زیبا این ایده مشخص شده :تو این پترن ، طراحی کد ها به نحوی هست که انگار از implementation هامون یک پلی به Abstraction زده شده و تغییراتی که به اپلیکیشن تحمیل میشه به صورت مجزا در هر لایه  هندل میشن و تاثیری روی اون طرف پل ندارن :)امیدوارم مقاله براتون مفید بوده باشه.</description>
                <category>پوریا سیفی</category>
                <author>پوریا سیفی</author>
                <pubDate>Fri, 18 Aug 2023 14:12:44 +0330</pubDate>
            </item>
                    <item>
                <title>دیزاین پترن Adapter به زبان ساده  ?</title>
                <link>https://virgool.io/@PouriaSeyfi/%D8%AF%DB%8C%D8%B2%D8%A7%DB%8C%D9%86-%D9%BE%D8%AA%D8%B1%D9%86-adapter-%D8%A8%D9%87-%D8%B2%D8%A8%D8%A7%D9%86-%D8%B3%D8%A7%D8%AF%D9%87-sygqdpi81fma</link>
                <description>حتما واژه ی اداپتور به گوشتون خورده... کار این وسیله اینه که ولتاژ برق شهری رو به اندازه مورد نیاز برای وسیله های مورد نظر ما کاهش بده. در واقع سازگار کردن یه چیزی با چیز دیگه (به قول خارجی ها ادپته شدن :) )تو دنیای نرم افزار خیلی وقتا ها پیش میاد که دو کلاس مختلف  با هم سازگار نیستند و ما باید یه  Adapter بنویسیم که این سازگاری رو برامون تضمین کنه که دو کلاس بتونند با هم کار کنند و تعامل داشته باشند . ما برای اینکه لپتاپ خودمون رو شارژ کنیم مجبور نیستیم با پیچ گوشتی پریز رو باز کنیم و ولتاژ رو به اندازه  ظرفیت لپتاپ کم کنیم... یا مجبور نیستیم سوکت لپتاپ مون رو باز کنیم و یه کاری کنیم با ولتاژ شهری کار کنه. برای اینکار یه آداپتور (شارژر) ساخته شده که باعث میشه این برق شهری و لپتاپ بدون مشکل با هم کار کنند.دیزاین پترن Adapter هم دقیقا همین کار رو برای ما انجام میده. در واقع باعث میشه که دو تا کلاسی که با هم سازگار نیستند بتونند با هم کار کنند بدون اینکه مجبور باشیم به سورس کد دست بزنیم. پس اگر برق شهری رو کلاس الف در نظرم بگیریم و لپتاپ رو کلاس ب ، کلاس ادپتور باعث میشه این دو کلاس با هم سازگار بشند. به همین سادگی...خب حالا یک مثال تو دنیای نرم افزار رو بررسی کنیم : فرض کنیم نرم افزار ما قابلیت لاگ گیری داره و ما تا الان لاگ هامون رو توی فایل ذخیره میکردیم :
interface Logger {
    public function logInfo($message);
    public function logWarning($message);
    public function logError($message);
}

class FileLogger implements Logger {
    public function logInfo($message) {
        // Log info message to a file 
    }
    public function logWarning($message) {
        // Log warning message to a file 
    }
    public function logError($message) {
        // Log error message to a file
    }
}

// Usage
$fileLogger = new FileLogger();
$fileLogger-&gt;logInfo(This is an informational message);
$fileLogger-&gt;logWarning(This is a warning message);
$fileLogger-&gt;logError(This is an error message);
حالا فرض کنید شرایطی پیش میاد که قراره ما  از یه لاگ گیری دیگه هم پشتیبانی کنیم .مثلا قرار باشه لاگ ها توی دیتابیس  مونگو ذخیره بشن به جای فایل. توجه داشته باشیم که این لاگر  لزوما توسط ما نوشته نشده و میتونه یه پکیج یا کتابخونه شخص ثالث باشه.اینکه مکانیزم ثب لاگ ها به چه صورتی هست تو این مقاله برای ما مهم نیست بنابراین تو کامنت فقط اشاره میکنیم که قراره چه اتفاقی بیفته : class MongoLogger {
  public function info($message) {
        // Log info message using the MongoDB logger
  }
  public function warn($message) {
     // Log warning message using the MongoDB logger
   }
  public function error($message) {
    // Log error message using the MongoDB logger
   }
}اگر دقت کنید متوجه میشید که MongoLogger با لاگر قبلی ما یه تفاوتی در اسم متد ها داره. در واقع ما تا الان به این صورت لاگ ثبت میکردیم :$logger-&gt;logInfo(&#039;info message&#039;);حالا MongoLogger داره به ما تحمیل میکنه که به این صورت ثبت کنیم : $logger-&gt;info(&#039;info message&#039;);خب پس یه ناسازگاری تو سیستم به وجود اومده ! برای اینکه این ناسازگاری رو درست کنیم باید یک Adaptor بنویسیم : class MongoLoggerAdapter extends MongoLogger implements Logger {
    public function logInfo($message) {
        $this-&gt;info($message);
    }
    public function logWarning($message) {
        $this-&gt;warn($message);
    }
    public function logError($message) {
        $this-&gt;error($message);
    }
}کلاس MongoLoggerAdapter به ما این اجازه رو میده که  ثبت شدن لاگ های کتابخونه شخص ثالث رو با نحوه ی لاگ گیری اپلیکیشن خودمون سازگار کنیم.خب تا اینجای کار با کار اصلی ادپتور ها آشنا شدیم. برای پیاده سازی این دیزاین پترن دو روش مختلف وجود داره : Class AdapterObject Adapter پیاده سازی که تا اینجا انجام دادیم نوع اول بود. همونطور که واضح هست تو این حالت ما برای ساخت ادپتور از ارث بری استفاده کردیم. اما قبل از اینکه بریم سراغ پیاده سازی نوع دوم ادپتور، شما رو دعوت میکنم به تفکر و تعمق به یک جمله زیر :Favor &quot;Object Composition&quot; over &quot;Class Inheritance&quot;هرچقدر میتونید برای درک این جمله زمان بذارید...  این جمله بیان میکنه که در طراحی سیستم های نرم افزاری تا جایی که میتونید سعی کنید به جای ارث بری از object composition استفاده کنید.در واقع اولویت رو به object composition بدید. این رویکرد اشاره به ساخت ابجکت های پیچیده با استفاده از ابجکت های ساده تر داره که قابلیت استفاده مجدد و انعطاف پذیری بیشتری رو به ما میده و باعث میشه کنترل بیشتری داشته باشیم.مثلا برای ساخت ادپتر ، میتونیم به جای ارث بری،  ابجکت MongoLogger رو تو متد سازنده ادپتر پاس بدیم. تو کدی که بالا نوشتیم فرض کنید که MongoLogger متدی داره که ما اصلا نیاز نداریم تو ادپتر داشته باشیمش ولی خب ارث بری به ما تحمیل میکنه که تمام متد ها رو ادپتر هم داشته باشه. این یکی از ایرادات ارث بری هست. اساسا در دنیای شی گرایی ارث بری  مشکلاتی رو تحمیل میکنه که باید در مقالات دیگه بهش بپردازیم...حالا با توجه به این توضیحات بریم به یه شکل دیگه ادپتور خودمون رو پیاده سازی کنیم : 
class MongoLoggerAdapter implements Logger {
    private $mongoLogger;
    public function __construct(MongoLogger $mongoLogger) {
        $this-&gt;mongoLogger = $mongoLogger;
    }
    public function logInfo($message) {
        $this-&gt;mongoLogger-&gt;info($message);
    }
    public function logWarning($message) {
        $this-&gt;mongoLogger-&gt;warn($message);
    }
    public function logError($message) {
        $this-&gt;mongoLogger-&gt;error($message);
    }
}

// Usage
$mongoLogger = new MongoLogger();
$adapter = new MongoLoggerAdapter($mongoLogger);
$adapter-&gt;logInfo(This is an informational message);
$adapter-&gt;logWarning(This is a warning message);
$adapter-&gt;logError(This is an error message);خب همونطور که مشخص هست ما بدون استفاده از ارث بری تونستیم ادپتور مورد نظرمون رو بسازیم.  در آخر لازمه اشاره کنیم که این دیزاین پترن در دسته بندی دیزاین پترن های Structural قرار میگیره. امیدوارم مقاله براتون مفید بوده باشه :)مقالات دیگر در مورد دیزاین پترن ها : https://virgool.io/@PouriaSeyfi/%D8%AF%DB%8C%D8%B2%D8%A7%DB%8C%D9%86-%D9%BE%D8%AA%D8%B1%D9%86-template-method-%D8%A8%D9%87-%D8%B2%D8%A8%D8%A7%D9%86-%D8%B3%D8%A7%D8%AF%D9%87-vhmsfebmbwyk  </description>
                <category>پوریا سیفی</category>
                <author>پوریا سیفی</author>
                <pubDate>Mon, 14 Aug 2023 03:58:00 +0330</pubDate>
            </item>
                    <item>
                <title>دیزاین پترن Template Method به زبان ساده ?</title>
                <link>https://virgool.io/@PouriaSeyfi/%D8%AF%DB%8C%D8%B2%D8%A7%DB%8C%D9%86-%D9%BE%D8%AA%D8%B1%D9%86-template-method-%D8%A8%D9%87-%D8%B2%D8%A8%D8%A7%D9%86-%D8%B3%D8%A7%D8%AF%D9%87-vhmsfebmbwyk</link>
                <description>به نظر من فقط زمانی مفهوم یک دیزاین پترن برای ما جا میفته که تو محصول واقعی ازش استفاده بکنیم.از طرفی موقع کد زدن تو محیط واقعی و عملی که میشه کاملا سردرگم هستیم و نمیتونیم شرایط به وجود اومده رو با چه دیزاین پترنی مطابقت بدیم، مگر اینکه بتونیم از مثال هایی که از قبل تو ذهن مون پردازش کردیم استفاده کنیم و شباهت هایی رو کشف کنیم. تو این سری مقالات قصد دارم در مورد دیزاین پترن های مهم مثال هایی رو مطرح کنم که راحت تر بفهمیم در چه شرایطی قابل استفاده و کارا هستند.  برای اولین مورد پترن Template Method رو مناسب دیدم. تو این مقاله سعی میشه در ابتدا یک مثال ساده تو دنیای واقعی مطرح بشه و در نهایت به مثال های عملی تر در محیط های واقعی بپردازیم.  ⚠️ برای خوندن این مقاله لازمه که مفاهیم مقدماتی از شی گرایی رو بلد باشید .  خب تو قدم اول برنامه نویسی رو کنار بذاریم و یک مثال تو دنیای واقعی بزنیم :فرض کنید یه مغازه ساندویچ فروشی داریم و قراره همبرگر و  هات داگ بفروشیم. پس کار اصلی ما درست کردن ساندویچ هست. درست کردن ساندویچ  شامل مراحل میشه :۱ - برداشتن نون باگت ?۲- گذاشتن مواد اولیه (همبرگر یا هات داگ ) ?۳ - گذاشتن گوجه و خیارشور و کاهو ?۴ - ریختن سس روی ساندیچ  ?خب فرض کنیم مواد اولیه رو خریداری کردیم . قاعدتا شما برای هر نوع ساندویچی نون باگت ها ،گوجه ،خیارشور، کاهو و سس رو یک جای مشترک میذارید. سوال : آیا منطقی هست که شما بگید این خیارشور و گوجه و کاهو و ... برای همبرگره، این یکی گوجه و کاهو ها برای هات داگ؟  قطعا جواب این سوال نه هست ! بنابراین برای مراحل ۱ و ۳ و ۴ ما یک کار مشخص و مشترک انجام میدیم . حالا همین مثال ساده رو ببریم تو کد زیر : &lt;?php

abstract class SandwichClass
{

// template method
final public function make(): void
    {
        $this-&gt;stepA();
        $this-&gt;stepB();
        $this-&gt;stepC();
        $this-&gt;stepD();
    }

protected function stepA(): void { echo &amp;quotبرداشتن نون باگت&amp;quot  }

abstract protected function stepB(): void

protected function stepC(): void { echo &amp;quotگذاشتن گوجه و خیارشور و کاهو&amp;quot  }

protected function stepD(): void { echo &amp;quotریختن سس روی ساندیچ&amp;quot  }

}
خب توی کدی که مشاهده میکنید مراحل مختلف درست کردن ساندویچ آورده شده. مرحله اول و سوم و چهارم که مشترک بود رو توی کلاس abstract گذاشتیم و تو یه کلاس که قراره همه ساندویچ ها ازش استفاده کنند  هندل کردیم. قرارمون هم همین بود (کارای تکراری و مشترک). میمونه همبرگر یا هات داگ بودن ساندوچ، که مشترک نیستند ولی حتما باید مطمئن باشیم مرحله دو هم انجام میشه .همونطور که میدونید متد های از نوع abstract حتما باید توسط کلاس های زیرین پیاده سازی بشن. بنابراین ما کلاس هایی که از این کلاس ساندویچ  ارث بری میکنند رو مجبور کردیم این متد stepB رو پیاده سازی کنند (نمیشه که ساندویچ خالی بدیم دست مردم)حالا میتونیم برای همبرگر و هات داگ هم دو تا کلاس متفاوت بنویسیم که کارشون فقط درست کردن همون ساندویچ هست (اینجا اصل اول سالید هم داریم رعایت میکنیم که هر کلاسی وظیفه ش یه چیز باشه) کلاس های همبرگر و هات داگ هم به این صورت نوشته میشه :class HamburgerClass extends SandwichClass
{
    protected function stepB(): void
    {
         echo &amp;quotدرست کردن همبرگر&amp;quot
    }
}class HotdogClass extends SandwichClass
{
   protected function stepB(): void  
   { 
       echo &amp;quotدرست کردن هات داگ&amp;quot   
   } 
} آیا منطقی بود که هر کدوم ازین کلاس ها اون سه مرحله مشترک دیگه رو پیاده سازی کنند و کد تکراری تولید کنیم؟  قطعا خیر. حالا اگر ما بخواهیم یه ساندویچ جدید هم بسازیم مثلا فلافل، فقط کافیه که یک کلاس فلافل بسازیم و تغییری تو کد های قبلی ایجاد نمیشه (اینم اصل دوم سالید)در واقع منطق اصلی کار ما (همون چهار تا مرحله) فقط یک جا هندل میشه. توی این پترن، ما حتما یک کلاس Abstract  داریم که یک متد مهم  (template method)  داره . اسم این دیزاین پترن هم به خاطر همین متد template method نام گذاری شده.  کار متد تمپلت (که تو مثال ما اسم این متد make هست) اینه که  مراحل اصلی الگوریتم رو به ترتیب خاصی اجرا میکنه . اگر دقت کنید نوع این متد final هم هست. دلیلشم این هست که کلاس های زیرین اجازه ندارن این متد رو تغییر بدن.خب همونطور که دیدید ما در عمل هیچ کار عجیب غریبی نکردیم فقط یه استفاده ساده از Abstract کلاس داشتیم. من معتقد هستم که خیلی وقت ها بدون اینکه بدونیم از یه سری پترن ها استفاده میکنیم  (به شرطی که با ایده های شی گرایی آشنا باشیم و به اصولی مثل سالید پایبند)تعریف اصلی دیزاین پترن تمپلت : The Template Method design pattern is a behavioral pattern that defines the skeleton of an algorithm in a superclass but lets subclasses override specific steps of the algorithm without changing its structure.با توجه به این تعریف و مثال خودمون اگه ساندویچ درست کردن یه الگوریتم باشه، ما مراحلش رو توی کلاس ساندویچ (superclass) اجرا کردیم و اجازه دادیم کلاس های همبرگر و هات داگ (subclasses) متد مرحله دو رو override کنند. این پترن تو دنیای واقعی بسیار پرکاربرد هست . چون خیلی وقت ها ما انواع مختلفی از آبجکت ها رو میسازیم که در عمل منطق شون واحد هست. مثال های عملی :مثال یک : ساختن درگاه بانکی که انواع مختلفی از درگاه ها رو ساپورت میکنه  : تو برنامه ی ما فرآیند پرداخت یک الگوریتم و منطق مشترک داره. میتونیم برای هر بانکی یه کلاس بنویسیم و بانک های مختلف باید از الگوریتم ما تبعیت کنند.  مثلا همه کاربرا باید۱ - درخواست خرید ثبت کنند۲ - به یک درگاه پرداخت متصل بشن و بعد از فرآیند پرداخت ریدایرکت بشن به برنامه ما ۳ - پرداخت شون تایید بشه مثال دو : ساختن یک اکسپورت که انواع مختلفی از خروجی ها رو داره : الگوریتم ساخته شدن اکسپورت  (super class)  انواع مختلفی از اکسپورت ها مثل پی دی اف ، اکسل و ... (sub classes) مثال سه : ساختن یک ناتیفیکیشن که با اشکال مختلفی ارسال میشه : الگوریتم ساخته شدن ناتیفیکیشن یک کلاس abstract هست که منطق مشترکی داره (super class) و انواع مختلفی از ناتیفیکیشن میتونه ساخته بشه مثل ایمیل، پیامک، تلگرام و ...  (sub classes) مثال چهار : فرآیند احراز هویت  با استفاده از شبکه های اجتماعی دیگر :فرآیند احراز هویت یک منطق مشترک (super class) داره اما ورود و ثبت نام با گوگل ، گیت هاب ، توئیتر میتونه پیاده سازی های مختلفی داشته باشه (sub classes) تو همه این مثال ها منطق اصلی یک روال مشخص داره که کلاس های مختلف میتونن برخی از مراحل رو تغییر بدن و مجبورن اون روال رو پیاده سازی کنند.امیدوارم این مقاله مفهوم رو به خوبی رسونده باشه و به دردتون بخوره</description>
                <category>پوریا سیفی</category>
                <author>پوریا سیفی</author>
                <pubDate>Fri, 10 Mar 2023 19:01:50 +0330</pubDate>
            </item>
                    <item>
                <title>بررسی Facades در لاراول</title>
                <link>https://virgool.io/@PouriaSeyfi/%D8%A8%D8%B1%D8%B1%D8%B3%DB%8C-facades-%D8%AF%D8%B1-%D9%84%D8%A7%D8%B1%D8%A7%D9%88%D9%84-zdzo2vjrdbec</link>
                <description>خب تو این مقاله میخوایم ببینیم اصلا فساد چیه؟ و قراره چه مشکلی رو برای ما حل بکنه! اگه با فریم ورک لاراول کار کرده باشید حتما میدونید که یکی از مفاهیم مهم و کلیدی در لاراول، فساد ها هستند. به طور کلی فساد ها این امکان رو فراهم میکنند که خیلی سریع و راحت از سرویس کانتینر یه کلاس هایی رو بیرون بیاریم و استفاده بکنیم.  اگه احساس میکنید  مفهموم سرویس کانتینر براتون مبهم هست، ابتدا لازمه این ابهام رو برطرف بکنید. پیشنهاد میکنم مقاله قبلی من در مورد سرویس کانتینر لاراول رو مطالعه کنید. ابتدای کار چند مورد از فساد ها رو مرور کنیم : Log::info(&#039;info text&#039;);
DB::table(&#039;users&#039;)-&gt;get();
Route::get(&#039;/&#039;);
Cache::get(&#039;key&#039;);احتمالا خیلی با این موارد سر و کار داشتید اما تا حالا براتون سوال شده که ما چرا انقد از این حالت استاتیک (یعنی :: ) تو فراخوانی کلاس ها استفاده میکنیم؟ آیا همه این توابع  واقعا به صورت استاتیک فراخوانی میشن؟؟برای جواب دادن به این سوال مهم باید ببینیم درون فساد ها واقعا چه اتفاقی داره میفته. خب اولین جمله داکیومنت لاراول در مورد فساد ها اینه :Facades provide a &quot;static&quot; interface to classes that are available in the application&#x27;s  IoC container  این جمله میگه که فساد ها یه بستری فراهم میکنن که ما استاتیک طوری به کلاس های مختلف موجود در سرویس کانتینر دسترسی داشته باشیم. حالا سوال اصلی اینه که چرا  از طریق متد استاتیک فراخوانی میشن؟ در جواب باید بگم که همونطور که درسته این فساد ها شبیه فراخوانی متد های استاتیک هستند ولی این فقط ظاهر ماجراست...اگه یه نگاهی به مسیر vendors / laravel/ framework / src/ illuminate / support / Facades بندازید میبینید که همه خوبای لارول اینجا جمع شدن :) همه این کلاس ها از  vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php  ارث بری میکنن و فقط یک متد getFacaseAccessor دارن. حالا اتفاقی که پشت پرده میفته اینه که لاراول با استفاده این فایل ها و سینتکس استاتیک (همون ::) میاد از یه سری کلاس نمونه میسازه و اونو تو کل اپلیکیشن در اختیار ما قرار میده (اشاره به سرویس کانتینر). حالا چرا استاتیک ؟ صرفا جهت راحتی و تمیز بودن و قشنگی!Facades are just fancy ways of pulling things from the containerمگه میشه یه سری متد به ظاهر استاتیک بنویسی ولی تو واقعیت استاتیک نباشن؟ بله!به عنوان مثال برای ثبت لاگ ما به این صورت عمل میکنیم : Log::info(&#039;info text&#039;);این یعنی اینکه سرویس کانتینر لطفا برو فایل Logger.php رو پیدا کن و ازش نمونه بساز  بعد متد info رو برام اجرا کن. ضمنا ممکنه بازم بخوام لاگ بگیرم پس حواست باشه دفعه بعدی دیگه نمونه سازی نکنی (singleton) پس همین نمونه رو برام برگردون. حالا سرویس کانتینر از کجا فهمید که  فایل Logger.php رو پیدا کنه؟ این همون کاریه که متد getFacaseAccessor به همراه LogServiceProvider انجام میده. اگه این قسمت براتون مبهمه احتمالا با سرویس کانتینر ها آشنا نیستید. پیشنهاد میکنم مقاله سرویس کانتینر رو مطالعه کنید.تصویر زیر همون متد info رو نشون میده که خیالتون راحت باشه هیچ خبری از متد استاتیک نیست.حالا چرا فساد این کار رو میکنه؟  چند دلیل برای این کار وجود داره . مهم ترینش اینه که اینجوری ما هر بار مجبور نیستیم تو قسمت های مختلف اپلیکیشن از کلاس های پر کاربرد نمونه سازی بکنیم و حتما میدونید که منظور از ساختن نمونه صرفا یه new کردن ساده نیست . ممکنه سازنده ها کلی منطق پیچیده داشته باشن. از بررسی درایور ها گرفته تا شرایط تست پذیری و کلی مسائل دیگه...یه جورایی لاراول اینجا از دیزاین پترن فساد هم استفاده کرده. “فساد” به معنی نمایه خارجی یا بیرونی هست و میشه گفت کارش اینه که پیچیدگی ها  جزییات اضافی داخل یه سیستم رو پنهان کنه.   خب حالا فهمیدیم که فساد لاراول فراتر از دیزاین پترن فساد هست و به نظر من خیلی نباید این دو تا رو با هم قاطی کرد. حالا اگه این سوال ذهنتون رو درگیر کرده که لاراول چطوری با سینتکس استاتیک پشت پرده نمونه سازی میکنه بیاید یه مقدار در مورد توابع استاتیک تو PHP صحبت کنیم. همونطور که میدونید برای اینکه به متغیر ها و توابع استاتیک موجود در یک کلاس دسترسی پیدا کنیم ، لازم نیست از اون کلاس شی بسازیم.  به کلاس زیر دقت کنید :&lt;?php
class Log {
  public static function info() {
          echo &amp;quotinfo&amp;quot
  }
}
خب اگه بخوایم واقعا به شکل استاتیک تابع info رو فراخوانی کنیم به این صورت عمل میکنیمLog::info();حالا فرض کنید کلا تابع info تو کلاس Log وجود نداشته باشه و ما بخوایم فراخوانی ش کنیم. چه اتفاقی میفته؟ خب معلومه با خطا (method not found) مواجه میشیم :) حالا بیاید ببینیم قبل از اینکه به خطا بخوریم آیا میتونیم خطا رو هندل بکنیم یا نه.احتمالا با متدهای مجیک در PHP آشنا باشید. مهم ترینش همون متدهای constructor کلاس ها هستند. اما مجیک فانکشن مورد نظر ما تو این مقاله callStatic__ هست. به کد زیر دقت کنید : public static function __callStatic($name, $args){
        return &#039;هرچی دلم خواست&#039;;
    }در واقع اگه این فانکشن تو کلاس ما وجود داشته باشه قبل از اینکه اون متد اصلا وجود خارجی داشته باشه و PHP بخواد بره به صورت استاتیک پیداش کنه این مجیک فانکشن اجرا میشه. بنابراین ما میتونیم همونجا هر مقداری دوست داشتیم براش برگردونیم. و اینجا همون جایی هست که لارول کارای مربوط به فساد رو انجام میده. مثلا از کلاس gh&#x27; نمونه میسازه ، درایور لاگ رو چک میکنه و ...و دقیقا معادل تعریفی که برای پترن فساد داشتیم ، پیچیدگی های اضافی رو از دید ما پنهان میکنه. استفاده از فساد ، مزایای دیگه ای مثل تست پذیری بهتر اپلیکیشن هم فراهم میکنه. در واقع میتونیم بفهمیم تو یه درخواست، آیا یک کلاس فراخوانی شده یا خیر؟ چنبار فراخوانی و با چه شرایطی فراخوانی شده و ...امیدوارم از این مقاله استفاده کرده باشید . </description>
                <category>پوریا سیفی</category>
                <author>پوریا سیفی</author>
                <pubDate>Sun, 20 Jun 2021 01:17:21 +0430</pubDate>
            </item>
                    <item>
                <title>سرویس کانتینر لاراول (IOC)</title>
                <link>https://virgool.io/@PouriaSeyfi/%DA%A9%D8%A7%D9%86%D8%AA%DB%8C%D9%86%D8%B1-%D8%B3%D8%B1%D9%88%DB%8C%D8%B3-%D9%84%D8%A7%D8%B1%D8%A7%D9%88%D9%84-ioc-prbfjjcaitkc</link>
                <description>حتما تا به حال خیلی تلاش کردید مفهموم service container رو بفهمید. شاید اولین جایی که بهش مراجعه کردید و نا امید هم شدید قسمت IoC Container تو مستندات سایت لاراول باشه اما بعید میدونم درک و اطلاعات کاملی دستگیرتون شده باشه.  از طرفی هم هیچوقت دلمون نمیخواد با نفمیدن موضوع به این مهمی کنار بیایم، چرا که درک مفهوم Laravel IoC container  برای انجام پروژه هایی تو سطح متوسط و بزرگ ، فهم هسته و کانسپت (ایده) لاراول و یا مشارکت در ریپازیتوری لاراول بسیار حیاتی و ضروریه...در واقع کسی که این مفهوم رو درک نکنه نمیتونه ادعای حرفه ای بودن تو فریم ورک لاراول رو داشته باشه. واقعیت امر اینه که اگر بخوایم این مفهوم رو به درستی متوجه بشیم باید یه مقدار از دورتر به ماجرا نگاه کنیم. پس با من همراه باشید که پرده از اسرار ioc بگشاییم :)برای درک بهتر این مطلب لازمه با شی گرایی تا حدودی آشنا باشید و حداقل مفاهیمی مثل Class , Interface رو خوب بشناسید. تو دنیای نرم افزار مفهومی به اسم  inversion of control  یا همون ioc وجود داره که صرقا تو فریم ورگ لاراول هم نیست. کار ioc مدیریت وابستگی های کلاس ها هست.  شاید واژه Dependency Injection (تزریق وابستگی) تو لاراول به گوشتون خورده باشه . اما این Dependency Injection واقعا چیه و اصلا چرا لازمه ؟ خب این اولین و مهم ترین سواله.کد زیر رو در نظر بگیرید :class FooBar {

    public function __construct(Baz $baz)
    {
        $this-&gt;baz = $baz;
    }

} فرض کنید قرار یه شی از این کلاس بسازیم . قاعدتا  باید به این شکل عمل کنیم :$fooBaz = new FooBar(new Baz);شاید گفتنش براتون تکراری باشه ولی واضحه که  اگه این وابستگی ها بیشتر از این حرفا باشه قطعا کدنویسی سخت و خسته کننده ای در طول پروژه به ما تحمیل میشه. خب بهتره اول یه راه تمیز تر با لاراول رو امتحان کنیم : $fooBar = App::make(&#039;FooBar&#039;);این شی دقیقا معادل شی اولی هست که ساختیم. اولین سوالی که اینجا پیش میاد اینه که تکلیف کلاس Baz چی میشه که تو متد سازنده کلاس FooBar اجباریه؟ سوال خوبیه :) وقتی از مدیریت وابستگی توسط لاراول صحبت میکنیم دقیقا به همین اتفاق اشاره داریم. خب اینکه چطور این اتفاق افتاد برمیگرده به کدهای ریپازیتوری Container تو سورس کد لاراول. فعلا در همین حد بدونید که لاراول از یه ویژگی تو خود PHP استفاده میکنه به نام Reflection Class که به واسطه ی این کلاس میشه فهمید داخل یه کلاس دیگه چه خبره.  مثلا میشه فهمید سازنده ی کلاس ما چه وابستگی هایی داره. بنابراین باراول ازین قابلیت PHP استفاده میکنه و تکلیف همه اون وابستگی ها رو مشخص میکنه و اینطوری میشه که تو کد بالا بدون اینکه ما به کلاس Baz اشاره ای بکنیم میتونیم از کلاس  FooBar شی بسازیم.خب فک میکنم تا اینجا قدم خوبی برداشتیم. سوال بعدی که احتمالا ذهن شما هم درگیر کرده اینه که خب که چی که این  وابستگی رو مدیریت میکنه؟ فقط قشنگی کد که ما موقع شی ساختن new نکنیم؟ اصلا من شاید بخوام سازنده کلاس ام رو خودم به فراخور نیازی که هر قسمت از برنامه ام داره خودم تعیین بکنم. چرا باید لاراول این کار رو انجام بده؟خب در پاسخ به این سوال ها باید بگم که قضیه جدی تر از این حرفاست. بریم سراغ یه مثال کوچیک: class MySQLConnection
{   
   public function connect()
   {
      var_dump(‘MYSQL Connection’);
   }
}

class PasswordReminder
{    
   private $dbConnection; 
   public function __construct(MySQLConnection $dbConnection) 
    {
      $this-&gt;dbConnection = $dbConnection;
    }
}تو این مثال ساده PasswordReminder همونطور که از اسمش پیداست قراره  فراموشی رمز رو برای ما هندل کنه. همونطور که مشخصه سازنده این کلاس به MySQLConnection  وابسته ست. حالا فرض کنید مجبور شیم به هر دلیلی دیتابیس رو از mysql به mongo تغییر بدیم (میدونم مثال خیلی عملی نیست فقط به عنوان یه چیزی که میشه لمسش کرد بهش فکر کنید). خب چه اتفاقی میفته؟آیا این تغییر در تمام جاهایی از پروژه که از mysql استفاده کردیم باید اعمال شه؟ اگر با اصول SOLID آشنا باشید. اصل آخر ینی همون Dependency Inversion Principle یا اصل وارونه کردن وابستگی (DIP) تاکید میکنه  که : الف: ماژول های سطح بالا نباید به ماژول های سطح پایین وابستگی داشته باشند. هر دو این ماژول ها باید به یک سطح انتزاعی (Abstraction) وابسته باشند.ب: Abstraction‌ها نباید به جزئیات وابسته باشند. جزئیات باید به Abstraction‌ها وابسته باشند.نمیخوام خیلی درگیر تعاریف تکراری و خسته کننده شیم. پس بیاید به یه شکل دیگه کدهای مثالمون رو تغییر بدیم !interface ConnectionInterface
{
   public function connect();
}

class MySQLConnection implements ConnectionInterface
{
 public function connect()
 {
   var_dump(‘MYSQL Connection’);
 }
}

class PasswordReminder
{
    private $dbConnection;
    public function __construct(ConnectionInterface $dbConnection)
    {
      $this-&gt;dbConnection = $dbConnection;
    }
}تو کد بالا اگر قرار باشه کانکشن رو از mysql به mongo تغییر بدیم هیچ خللی در روند برنامه پیش نمیاد. در واقع یکی از مزایای استفاده از اینترفیس ها همینه. اینجا ما سعی کردیم جزئیات ماژول سطح بالا ینی همون PasswordReminder رو به Abstraction‌ (منظور همون اینترفیس هست) وابسته کنیم نه ماژول سطح پایین (MySQLConnection). خب حالا که این موضوع برامون روشن شد بیاید این مثال رو تو بستر لاراول هم امتحان بکنیم . فرض کنیم  تو کلاس PasswordReminder یه متد به اسم doSomething داریم که قراره از طریق روت زیر فراخوانی شه :Route::post(&#039;remindPass&#039;, &#039;PasswordReminder@doSomething&#039;);به نظرتون  IOC  لاراول باز هم قادره  وابستگی ما رو هندل کنه ؟؟ پاسخ سوال منفیه و در صورت امتحان با ارور BindingResolutionException مواجه خواهیم شد.دلیل هم مشخصه وقتی کلاس PasswordReminder داره ساخته میشه جایی اشاره نکردیم که وابستگی ش چه کلاسی هست.( فقط به اینترفیس اشاره کردیم)خب راه حل چیه ؟!اینجاست که کم کم اهمیت سرویس کانتینر رو درک میکنیم. با فراخوانی کد زیر در متد register کلاس AppServiceProvider مشکل رفع میشهApp::bind(&#039;ConnectionInterface &#039;, &#039;MySQLConnection &#039;);در واقع با یک خط کد و فقط یکبار برای همیشه  (bind کردن توسط سرویس کانتینر) به لاراول فهموندیم که کانکشن مد نظر ما  mysql هست.  حتی میتونیم واژه &#x27;MySQLConnection&#x27; رو توی فایل های کانفیگ قرار بدیم. دقت کرده باشید این روند تو خیلی از قسمت های لاراول یا پکیج های دیگه هم اتفاق میفته. در واقع شما یه سری درایور دارید که فقط یک جا مشخص میکنید درایور مورد نظرتون چیه. مثلا درایور سشن در لاراول که میتونه فایل باشه، دیتابیس باشه یا ردیس باشه.حالا ما برای راحتی و انسجام کانفیگ ها، گاها میایم تو یه فایل مشخص میکنیم درایور ها رو. ولی پشت پرده کد های لاراول از اون ها برای bind کردن استفاده میکنه. یکی دیگه از قابلیت های مهم ioc تو لاراول استفاده از دیزاین پترن singleton هست. مثلا فرض کنید اتصال  به دیتابیس که زمان نسبتا بیشتری میخواد فقط یکبار در طی درخواست کاربر باید انجام بشه. یا به هر دلیلی تصمیم داریم کلاس یکبار ساخته شه و تا انتهای درخواست ازش استفاده کنیم. استفاده از متد singleton این کار رو برای ما ممکن میکنه. حتی با قابلیت هایی مثل contextual-binding میتونیم اشاره کنیم که برای کدوم کلاس ها کانکشن mysql و برای کدوم کلاس ها کانکشن mongo استفاده بشه.البته متد های دیگه ای برای سرویس کانتینر وجود داره که میتونید تو داکیومنت سایت اصلی بررسی کنید. مفهوم IOC عمدتا در طراحی فریم ورک ها مورد استفاده قرار میگیره و اگه دقت کنید خیلی از قسمت های لاراول دیده میشه و کاملا مشخصه که چقدر رو فرآیند توسعه تاثیر بسزایی میذاره. controllers و  event listeners و  middleware و... ازین ویژگی بهره میگیرن. فسادها و helper function ها هم که کدنویسی در لاراول رو برای ما خیلی راحت و شیرین کردند به همین صورت. دلیل این همه کاربرد هم یه جورایی برمیگرده به همون مدیریت صحیح و عالی وابستگی ها. امیدوارم با  خوندن این مقاله درک بهتری از ioc کسب کرده باشید. سعی میکنم مقاله رو به روز نگه دارم و هر چند وقت یکبار کامل تر کنم. این اولین مقاله نوشتاری من بود و امیدوارم کم و کاستی هاش رو ببخشید. اگر ایراد و اصلاحی هم وارده خوشحال میشم باهام در میون بگذارید.تندرست و پیروز باشید</description>
                <category>پوریا سیفی</category>
                <author>پوریا سیفی</author>
                <pubDate>Sat, 18 Apr 2020 05:28:38 +0430</pubDate>
            </item>
            </channel>
</rss>