الگوهای طراحی برای مشکلات و چالش های مختلفی که در یک نرم افزار به وجود می آرند راه حل هایی را ارائه میکنند. این راه حل ها یک سری اصول کلی دارد و ما به عنوان برنامه نویس باید این ها را طبق نرم افزاری که نوشته ایم پیاده سازی کنیم.
فکر میکنم بدیهی باشد اما لازم است همین ابتدا ذکر کنم که منظور از الگو های طراحی، طراحی ظاهری و گرافیک برنامه نیست. منظور از طراحی اینجا شیوهای است که برای ساخت نرم افزار و نوشتن کدها انتخاب می کنیم.
داشتن دانش اولیه درباره شی گرایی شرط اول ورود به دنیای الگوهای طراحی است. همه این الگو ها بر اساس شیگرایی پیاده سازی میشوند و بدون آن کار با دیزاین پترن ها غیر ممکن است.
گروه چهار یا Gang of Four خالق الگوهای طراحی
چهار برنامه نویس به نام های Erich Garma، John Vlissides، Ralph Johnson و Richard Helm
در کتابی به نام Design Patterns: Elements of Reusable Object-Oriented Software.
تجربیات خودشان از راه حل های مختلف تکرار شونده در توسعه نرم افزار را منتشر کردند. بعدا این کتاب به نام کتاب Gang of Four(گروه چهار نفره) معروف شد.
به همین خاطر این چهار نفر به نام سازنده های الگوهای طرحی شناخته می شوند.
چرا باید الگوهای طراحی را یاد بگیرم؟
احتمالا بدون یادگیری الگوهای طراحی هم قادر هستید به کار برنامه نویسی خودتان ادامه دهید.
اما به چند دلیل بهتر است برای یادگیری الگوهای طراحی وقت بگذاریم.
-بسیارزی از شرکت ها حداقل در آگهی استخدام خودشان ذکر می کنند که یکی از شروط مهم استخدام، آشنایی با الگوهای طراحی است.
-برای افزایش مهارت خودمان در برنامه نویسی حتما نیاز داریم ک ه این الگوها را بشناسیم. چه برای به کاربردن آنها و چه برای مشارکت بهتر در کدهای دیگران.
-از لحاظ کاربرد در برنامه نویسی وقتی نرم افزار از یک حدی بزرگتر می شود. با یک سری چالش ها در تغییر در codebase و افزودن فیچرها مواجه می شوید. اینها به خاطر این است که کدی که نوشتیم از اول بر اساس ایک راه حل استاندارد و تست شده نیست. حالا برای یک تغییر کوچک مجبوریم 3 جای دیگر را هم درست کنیم.
دیزاین پترن ها در سه بخش دسته بندی می شوند:
- الگوهای طراحی ساختاری (Structural Patterns)
- الگوهای طراحی ایجادی (Creational Patterns)
- الگوهای طراحی رفتاری (Behavioral Patterns)
دیزاین پترن های ساختاری
با استفاده از این الگوی های طراحی اشیا و کلاس ها طوری طراحی می شوند که در ساختارهای بزرگ قابل استفاده باشند.
الگوی طراحی آداپتور(َAdaptor Pattern)
این اگو به ما کمک می کند که بین اشیایی که اینترفیس آنها با یکدیگر سازگاری ندارند ارتباط برقرار کنیم.
فرض کنید که یک کلاس در نرم افزار برای ارسال نوتیفیکیشن از طریق ایمیل داریم. این کلاس از اینترفیس به نام notification تبعیت میکند.
حالا قرار است قابلیت ارسال نوتیفیکیشن از طریق پیامک را هم اضافه کنیم. اما کلاسی که برای ارسال پیامک داریم با اینترفیس notification سازگار نیست و ما می خواهیم بدون دست بردن در کد هر کدام از این کلاس ها این قابلیت را به نرم افزار اضافه کنیم.
در چنین شرایطی یک کلاس دیگر می سازیم که به عنوان Adaptor عمل می کند. از کلاسی که برای ارسال اس ام اس داشتیم در این کلاس جدید استفاده میکنیم. کلاس جدیدی که ساختیم باید از اینترفیس notification پیروی کند.
حالا هر موقع نیاز به ارسال پیامک داشتیم از کلاس آداپتور استفاده میکنیم.
الگوی طراحی bridge
الگوی bridge کلاسهای خیلی بزرگ را به کلاس های کوچکتر که رابطه parent و subclass دارند تقسیم می کند.
در این الگو یک interface خواهیم داشت که نام متدهایی که کلاس اصلی قرار است داشته باشد در آن نوشته شده.
یک abstract class هم داریم که در آن از interface ای که ساخته بودیم استفاده شده و بعضی از کلاسهایی که کار اصلی در نرم افزار را انجام می دهند از اینترفیس ساخته شده تبعیت می کنند. بعضی از آنها هم abstract class را extend می کنند.
الگوی طراحی composite
الگوی composite یک آبجکت را به ساختار درختی تبدیل میکند و بعد هر کدام از این ساختارها را میتوان به عنوان یک آبجکت جدید در نظر گرفت.
اینجا معمولا یک abstract class داریم که همه کلاس های دیگر آن را extend میکنند. کلاس های جدیدتری که ساخته می شوند هم کلاس های قبلی را extend میکنند و به همین شکل ساختار درختی ساخته می شود. یک مثال خوب، ساختار اشیا در صفحه html هستند.
الگوی طراحی decorator
الگوی decorator به ما این امکان را میدهد که یک رفتار جدید به یک آبجکت اضافه کنیم. بدون اینکه نیاز به extend کردن کلاس داشته باشیم.
الگوی طراحی Facade
این الگوی طراحی وقتی استفاده میشود که بخواهیم چندین کار پیچیده که در کلاس های مختلف صورت گرفته را پشت یک کلاس ساده پنهان کنیم. و در موقع نیاز فقط از این کلاس استفاده کنیم. وقتی از یک کتابخانه بزرگ و پیچیده استفاده میکنیم استفاده از الگوی Facade به درد میخورد.
الگوی طراحی Flyweight
الگوی Flyweight به ما امکان ساخت تعداد زیادی آبجکت را می دهد طوریکه مصرف حافظه سیستم کاهش یابد. چون به ازای هر آبجکت جدید حافظه در رم اشغال می شود و زمانی که تعداد آبجکت ها بالا برود ممکن است با مشکل منابع مواجه شویم.
الگوی طراحی Proxy
الگوی proxy این قابلیت را برای ما ایجاد میکند تا دسترسی به یک آبجکت را کنترل کنیم. در این روش یک کلاس جدید میسازیم که inteface کلاس اصلی را implement کند.
در constructor این کلاس، از کلاس اصلی استفاده میکنیم. هر زمان که قصد استفاده از کلاس اصلی را داشتیم باید از این کلاس جایگزین استفاده کنیم.
برای مثال این کلاس جدید میتواند بررسی کند که آیا اطلاعات مورد نیاز کاربر در کش(cache) وجود دارد یا خیر. تا نیازی به صدا زدن کلاس اصلی نباشد.
الگوهای ایجادی (Creational Patterns)
این الگو ها روش هایی را برای ساخت آبجکت ها معرفی می کنند که منجر به انعطاف پذیری بالاتر نرم افزار در تغییرات و همینطور استفاده مجدد از کدهای قبلی میشود.
الگوی طراحی Factory Method
برای ساخت آبجکت در برنامه نویسی از عبارت new استفاده میکنیم. در این الگو داخل یک متد از کلاس این کار را میکنیم. به خاطر همین به آن factory method (متد کارخانه) می گویند. یعنی متدی که مثل یک کارخانه وظیفه تولید شی را بر عهده دارد.
الگوی طراحی Abstract Factory
در این الگوی طراحی با استفاده از تعریف یک interface برای کلاس ها، متد ساخت شی را داخل interface قرار میدهیم تا هر کلاسی که قرار بود آن را پیاده سازی کند این متد را بسته به نوع کلاس بنویسد.
در الگوی Factory Method ما در هر کلاس یک متد داشتیم برای ساخت شی. اینجا هم به همین شکل خواهد بود با این تفاوت که کلاس ما یک اینترفیس را implement می کند. در این اینترفیس متد ساخت کلاس آورده شده و همه کلاسهای مرتبط باید آن را داشته باشند.
الگوی طراحی Builder
الگوی Builder این امکان را به ما می دهد که یک شی را در چند مرحله بسازیم.
گاهی اوقات یک کلاسی داریم که تعداد زیادی پارامتر در متد constructor آن قرار دارد. به چه علت این اتفاق افتاده؟ چون میخواستیم که موقع ایجاد شی این مقادیر به عنوان تنظیمات دریافت شوند.
شاید اصلا در برخی موارد به همه این مقادیر نیاز نداشته باشیم
حالا به جای این کار با استفاده از الگوی builder این امکان را داریم که فقط مقادیری را ست کنیم که به آن نیاز داریم.
$product = ProductBuilder->setPrice(100)->setInventory(10)->setWeight(2);
الگوی Builder اینجا به ما میگوید به جای اینکه یک کلاس برای هر کدام از این بخش ها بسازی و در هر کدام هم یک متد برای ساخت شی داشته باشی، کد مخصوص ساخت آبجکت را از کلاس خارج کن و در یک شی جدا قرار بده.
از این الگو وقتی استفاده می شود که قرار است آبجکتی بسازیم که از تعداد زیادی تنظیمات استفاده می کند و آوردن همه آنها در constructor امکان پذیر نیست.
الگوی طراحی Prototype
با استفاده از الگوی prototype میتوانیم از روی آبجکت ها کپی بگیریم بدون اینکه به کلاس آبجکت قبلی وابسته باشد.
الگوی طراحی Singleton
در الگوی طراحی singleton یک کلاس فقط یک شی می تواند داشته باشد. آبجکتی که با استفاده از این الگو ایجاد شده دیگر در جای دیگر نرم افزار نمی تواند جایگزین شود و هر بار که شی را ایجاد کنیم همان مقدار قبلی برای ما برگردانده میشود.
الگوهای رفتاری (Behavioral Patterns)
این دیزاین پترن ها مربوط به نحوه عملکرد اشیا و ارتباطشان با یکدیگر هستند.
الگوی طراحی Chain of Responsibility
این الگو به ما اجازه می دهد که درخواستی که از طرف کاربر نرم افزار ارسال شده را به بخش های مختلف نرم افزار به ترتیب ارسال کنیم و هر کدام از آنها بتوانند به این ریکوئست پاسخ مورد نظر ما را بدهند. یک مثال خوب از این الگو استفاده از middleware ها در ریکوئستهای HTTP است.
الگوی طراحی Command
الگوی command یک ریکوئست یا یک عملیات خاص را به آبجکت تبدیل می کند. و همه اطلاعات مورد نیاز در مورد آن ریکوئست در داخل آن آبجکت وجود دارد.
الگوی طراحی Iterator
وقتی مجموعهای از آبجکت ها راداریم که همان collection ها هستند، باید روشی داشته باشیم که به عناصر مختلف این مجموعه به راحتی دسترسی پیدا کنیم. الگوی iterator این کار را انجام میدهد.
الگوی طراحی Mediator
الگوی mediator باعث کاهش وابستگی آبجکتها به یکدیگر میشوند. در این الگو یک آبجکت واسط، وظیفه ارتباط بین آبجکت های دیگر را بر عهده میگیرد.
الگوی طراحی Memento
الگوی طراحی memento این قابلیت را در اختیار ما میگذارد که یک آبجکت را به حالت قبلی خودش برگردانیم. انگار یک بکاپ از آبجکت گرفته باشیم و در آینده در صورت نیاز آن را بازیابی کنیم.
الگوی طراحی Observer
با استفاده از الگوی observer می توانیم تغییرات آبجکت ها را زیر نظر بگیریم و با تغییر هر کدام عملیات مورد نظر را انجام دهیم.
الگوی طراحی State
با استفاده از الگوی State یک آبجکت میتواند رفتارش را بر اساس تغییر حالت داخلی آبجکت عوض کند.
الگوی طراحی Startegy
در الگوی strategy رفتارهای مختلفی که قرار است در نرم افزار انجام شود در داخل آبجکت ها قرار میدهیم. طوریکه این قابلیت ها قابل تعویض با یکدیگر باشند.
الگوی طراحی Template Method
در این الگوی طراحی یک الگوریتم داخل یک کلاس تعریف می شود و کلاس های زیرمجموعه می توانند بخش های مخنلف از کلاس را با توجه به نیاز نرم افزار جایگزین کنند. اما ساختار کلی الگوریتم باید حفظ شود.
الگوی طراحی Visitor
الگوی visitor این امکان را ایجاد میکند. که به کلاس های موجود در نرم افزار یک قابلیت جدید اضافه کنیم بدون اینکه به کدهای نوشته شده دست بزنیم.
جمع بندی
سعی کردم یک توضیح کلی در مورد الگوی های طراحی در توسعه نرم افزار داده باشم.
البته توضیح هرکدام از این الگوها باید مفصل داده شود که به مرور در به روزرسانی های بعدی به این مطلب اضافه میکنم.