تا کنون 23 الگوی طراحی برای رفع مشکلات متداول در برنامه نویسی شی گرا توسعه داده شده است که یکی از آنها الگوی طراحی کارخانه یا Factory Method است. الگوی طراحی کارخانه در دسته الگوهای طراحی سازنده یا Creational قرار دارد و به شما در مدیریت ایجاد اشیا کمک میکند. این الگوی طراحی، راهکاری در اختیار برنامه نویسان قرار میدهد تا آنها را قادر سازد که بدون اینکه کلاس دقیق یک شی را مشخص کنند آن را ایجاد کنند و به استفاده از آن بپردازند. در ادامه این مقاله با الگوی طراحی Factory Method آشنا خواهیم شد و خواهیم دید چه زمانی استفاده از این الگوی طراحی در کدنویسی به کمک ما خواهد آمد.
چرا باید از الگوی طراحی Factory استفاده کنیم
در بعضی موارد اپلیکیشنهای ما بسیار بزرگ و پیچیده هستند و یا در آینده گسترش خواهند یافت. معمولا این اپلیکیشنها دارای تعداد خیلی زیادی کلاس (Class) هستند که از همه آنها نمونه و شی (Object) ساخته میشود. تصور کنید که اپلیکیشن شما دارای 500 کلاس باشد که از هر کدام از آنها باید به صورت میانگین 10 شی و نمونه ساخته شود. بنابراین در نرم افزار حدود 5000 هزار شی از کلاسها مختلف ساخته شده است. مثلا کلاسی مثل User که در سرتاسر اپلیکیشن مورد استفاده قرار میگیرد.
بنابراین اگر مثلا بخواهیم به Constructor مربوط به کلاس User پارامتری جدید اضافه کنیم، باید کلاس User را تغییر دهیم. این کار باعث میشود که در تمام پروژه، هر جایی که از آن کلاس شی ای ساخته شده است پارامتر جدید را مقداردهی و اضافه کنیم که کاری بسیار دشوار و زمان بر خواهد بود. اما با استفاده از الگوی طراحی Factory برای ساخت اشیا کارخانه ای خواهیم ساخت که وظیفه ساخت اشیا از کلاسهای مختلف را بر عهده دارد. با این کار دیگر نیازی به ساخت شیها با استفاده از کیورد new به صورت جداگانه نخواهیم داشت و کافی است برای ساخت اشیا از کارخانه ساخت آن کلاس استفاده کنیم.
مثلا برای ساخت شیها و نمونه هایی از کلاس User از Userfactory استفاده میکنیم. با این کار اگر نیاز به اعمال تغییراتی در کلاس مورد نظر خود داشته باشیم، کافی است تغییرات در کارخانه یا Factory مربوط به آن کلاس اعمال کنیم. پس از این عمل، تغییرات اعمال شده توسط کارخانه بر تمام کلاسهای ساخته شده در آن، لحاظ میشوند.
مثالی از کاربرد الگوی طراحی Factory
تصور کنید که وظیفه طراحی نرم افزاری برای مدیریت حمل و نقل اجناس تولیدی یک کارخانه بر عهده شما باشد. اولین نسخه ای که از این نرم افزار میسازید فقط میتواند حمل و نقل جاده ای را مدیریت کند. بنابراین بخش عمده ای از کدهای نوشته شده توسط شما در کلاس کامیون (Truck) نوشته شده اند. سپس بعد از مدتی نرم افزاری که طراحی کرده اید مورد توجه کاربران و مدیران کارخانه قرار میگیرد و به این دلیل تعداد زیادی درخواست برای توسعه نرم افزار به منظور پشتیبانی از مدیریت حمل و نقل دریایی دریافت میکنید.
قطعا اولین سوالی که در ذهن شما شکل میگیرد مربوط به چگونگی پیاده سازی ویژگیهای جدید مربوط به حمل نقل دریایی است. زیرا در حال حاضر، بیشتر کد شما در کلاس مربوط به کامیونها وارد شده است. اگر بخواهید کشتیها (Ships) را به نرم افزار خود اضافه کنید، نیازمند تغییر در تمام کدهای اصلی نرم افزار خواهید بود. اگر در آینده دوباره تصمیم بگیرید نرم افزار را گسترش دهید، همچنین با این چالشها مواجه خواهید شد. اگر بخواهید این چالشها را به صورت سنتی حل کنید، نرم افزار شما انعطاف پذیر نخواهد بود و امکان دارد با مشکلات زیادی مواجه شود.
چه زمانی باید از الگوی طراحی Factory استفاده کنیم
کاربرد این الگوی طراحی برای شرایطی است که چندین کلاس ما از یک کلاس دیگر ارث بری کرده باشند و معمولا از آن کلاس نمونه یا شی ساخته میشود. همچنین این الگوی طراحی در موارد دیگر هم نیز استفاده میشود. این موارد عبارتند از :
- کلاس هایی داشته باشیم که از آنها شیهای زیادی ساخته میشود. با این کار برنامه نویس دیگر اشیا را ایجاد نخواهد کرد بلکه تمام مسئولیت ایجاد کلاس را به Factory Method واگذار میکند.
- قبل از ایجاد شی هایی که نرم افزار با آنها کار میکند، نوع و وابستگی مربوط به آن ها را ندانید.
- می خواهید با استفاده از اشیا موجود و جلوگیری از ساختن دوباره آن ها، در منابع سیستم صرفه جویی کنید.
پیاده سازی الگوی طراحی Factory
در این بخش به بررسی مراحل پیاده سازی الگوی طراحی Factory میپردازیم، سپس با استفاده از زبان برنامه نویسی PHP این الگو را در قالب یک مثال برای تولید ماشینهای سواری پژو 405 و سمند پیاده سازی خواهیم کرد. در این مثال با استفاده از الگوی طراحی کارخانه دیگر نیازی به تعیین ویژگیهای هر ماشین در زمان تولید آن به صورت تک به تک نخواهیم داشت. زیرا با ساخت کارخانه تولیدی ماشینهای سواری و مشخص کردن ویژگیهای هر یک از آن ها، وظیفه ساخت این خودروها بر عهده کارخانه خواهد بود. مراحل پیاده سازی این الگو عبارتند از :
- ابتدا باید یک Interface تعریف کنیم که در آن توابعی تعریف شود که در همه اشیا مشترک و کاربردی است. سپس تمام اشیا باید از یک Interface پیروی کنند.
- باید یک تابع به عنوان کارخانه سازنده (Factory) آن شی در کلاسش اضافه شود. نوع متغیری که این تابع Return میکند باید با Interface که در بخش قبل ساخته شد، مطابقت داشته باشد.
- در کدهای نوشته شده هرجایی که اشیا توسط روش سنتی (به وسیله کیورد new) ایجاد شده اند باید پیدا شوند و برای ساخت آنها از تابع کارخانه سازنده آنها استفاده شود.
- باید مجموعه ای از کلاسهای فرزند سازنده (creator) برای انواع اشیایی که کارخانه میسازد، تعریف شوند. سپس در این کلاس ها باید تابع کارخانه بازنویسی (Override) شود تا اصولی که در این تابع تعریف شده اند، به شکل مورد نیاز تغییر داده شوند. مثلا اگر در نحوه ساخت یک خودروی سواری و خودروی باربری تفاوتی وجود دارد، در کلاسهای مربوط به خود این موضوع در نظر گرفته شود.
- اگر انواع مختلف و زیادی از اشیا وجود دارند که از نظر شما ساختن کلاسهای فرزند برای همه آنها منطقی به نظر نمیرسد و دارای ویژگیهای مشترکی هستند، میتوانید آن ویژگی را در کلاس والد وارد کنید و از تعریف مکرر آن در کلاسهای فرزند خودداری کنید.
- اگر مشاهده کردید میان اشیای ساخته شده توسط تابع کارخانه هیچ ویژگی مشترکی وجود ندارد و تابع کارخانه خالی مانده است، میتوانید آن را به صورت abstract تعریف کنید. همچنین اگر خلاف این امر صادق بود و ویژگی در این تابع باقی ماند، آن ویژگی را میتوان، یک ویژگی پیشفرض برای اشیا در نظر گرفت.
<?php namespace Web7learn\FactoryMethod\CarFactory; /** * The CarFactory class declares the carfactory method that is supposed to return an * object of a Car class. The CarFactory's subclasses usually provide the * implementation of this method. */ abstract class CarFactory { /** * Note that the CarFactory may also provide some default implementation of the * carfactory method. */ abstract public function buildcar(): Car; /** * Also note that, despite its name, the CarFactory's primary responsibility is * not creating Cars. Usually, it contains some core business logic that * relies on car objects, returned by the buildcar method. Subclasses can * indirectly change that business logic by overriding the factory method * and returning a different type of Car from it. */ public function someOperation(): Type { //U can Call the buildCar method to create a car object and use that Here. } } /** * Concrete Car Factories override the factory method in order to change the * resulting car's type. */ class PeugeotFactory extends CarFactory { /** * Note that the signature of the method still uses the abstract Car * type, even though the concrete Car is actually returned from the * method. This way the CarFactory can stay independent of concrete Car * classes. */ public function buildcar(): Car { return new Peugeot405; } } class SamandFactory extends CarFactory { public function buildcar(): Car { return new Samand; } } /** * The Car interface declares the operations that all concrete Cars must * implement. */ interface Car { public function operation(): Type; } /** * Concrete Cars provide various implementations of the Car interface. */ class PeugeotFactory implements Car { public function operation(): Type { return "{Result of the Peugeot405}"; } } class SamandFactory implements Car { public function operation(): Type { return "{Result of the Samand}"; } }
اگر میخواهید بیشتر راجب الگوهای طراحی بدانید, مقالات زیر را مطالعه کنید
- دیزاین پترن چیست : الگوی طراحی یا Design Pattern چیست؟
- الگوی طراحی کارخانه انتزاعی
- الگوی طراحی پروتوتایپ
- الگوی طراحی Builder چیست و چه کاربردی دارد؟
- الگوی طراحی factory چیست
- singleton چیست
نتیجه گیری
پیاده سازی الگوی طراحی Factory برای نرم افزارهایی که امکان دارد در آینده گسترش یابند بسیار مفید است. پیاده سازی این الگوی طراحی در نرم افزارها به افزایش انعطاف آنها در برابر تغییرات بسیار کمک میکند. همچنین این الگو باعث بهینه سازی در مصرف منابع خواهد شد. نظر شما در مورد الگوی طراحی کارخانه چیست؟ آیا تاکنون از این الگوی طراحی در طراحی نرم افزارهای خود استفاده کرده اید؟