مثالی از الگوی طراحی کارخانه انتزاعی در دنیای واقعی
نتیجه گیری
دیزاین پترنها در کنار تمرکز بر حل مشکلات برنامه نویسی شی گرا، اهداف متفاوتی را دنبال میکنند. یکی از اهداف اصلی آن ها، افزایش خوانایی کدها و کاهش میزان کدنویسی است. الگوی طراحی کارخانه انتزاعی یا Abstract Factory جزو الگوهای طراحی سازنده (Creational) است که برای مدیریت ساخت اشیا از کلاسها توسعه داده شده است. این الگوی طراحی به شما اجازه میدهد که مجموعه ای از اشیا مرتبط را بدون نیاز به ساخت کلاسهای جداگانه و متعدد ایجاد کنید.
کاربرد الگوی طراحی کارخانه انتزاعی تا حدودی مانند الگوی طراحی Factory است. این الگوی طراحی معمولا زمانی استفاده میشود که کاربر به صورت دقیق از نوع شی ای که میخواهد ایجاد کند اطلاع نداشته باشد. اگر قصد دارید از این الگوی طراحی در فرآیند کدنویسی خود استفاده کنید، از شما دعوت میکنم تا در ادامه این مطلب همراه ما باشید.
چرا باید از الگوی طراحی Factory استفاده کنیم
تصور کنید که یکی از تولیدکنندگان محصولات اداری به منظور طراحی نرم افزاری به منظور فروش و مدیریت خط تولید محصولاتش به شما مراجعه میکند. در این نرم افزار محصولاتی از جمله انواع مبلمان، میز و... طراحی میشوند و سپس به فروش میرسند. در حالت پیش فرض نرم افزار شما باید به ازای هر محصول یک کلاس (Class) داشته باشد تا رفتار و وظایف مربوط به هر کدام از اشیا را برای خط تولید تعریف کند. از طرفی دیگر این محصولات معمولا با یکدیگر به فروش میرسند و مکمل یکدیگر هستند.
فرض کنید این کارخانه فقط شامل سه محصول میز، کاناپه و مبل است. پس کلاسهای مورد نیاز در نرم افزار عبارتند از: مبل + کاناپه + میز. همچنین در این کارخانه محصولات در سه سبک ساده، هنری و مدرن طراحی و ایجاد میشوند. از آنجایی که محصولات یک سبک معمولا با یکدیگر سفارش داده میشوند، باید آنها به صورت خانواده ای از محصولات مرتبط در نظر گرفته شوند.
بنابراین باید قابلیت افزودن محصولات یا سبکهای جدید را در نرم افزار در نظر گرفت. زیرا اگر این امکان پیش بینی نشده باشد در آینده باید کدهای موجود در نرم افزار تغییر یابند. زیرا فروشندگان محصولات معمولا خودشان لیست محصولات و کاتالوگها را به روز میکنند و منطقی نخواهد بود که هر بار که تغییری در محصولات ایجاد شود، کد اصلی نرم افزار نیاز به تغییر داشته باشد.
همچنین از طرفی دیگر باید در نرم افزار راهی برای فروش محصولات مرتبط با یکدیگر در نظر گرفته شود تا آنها با سایر محصولات خریداری شده از یک نوع و سبک باشند. زیرا اگر محصولات ارسال شده به مشتری از لحاظ سبک متفاوت باشند، قطعا از آنها ناراضی خواهد بود. فرض کنید که مشتری یک مبل، کاناپه و میز سفارش داده است و مبل از سبک ساده، کاناپه از سبک هنری و میز از سبک مدرن برای آن ارسال شوند. برای جلوگیری از چنین مشکلاتی در نرم افزارها، باید راه حلی در نظر گرفت.
راه حل الگوی طراحی کارخانه انتزاعی
راه حلی که الگوی کارخانه انتزاعی برای اینگونه مسائل پیشنهاد میدهد این است که یک Interface برای هر نوع محصول صرف نظر از سبکهای آن ایجاد شود. مثلا در این مثال باید سه Interface برای مبل، کاناپه و میز به صورت جداگانه تعریف شوند. سپس سبکهای مختلف از این محصولات باید از این Interfaceها پیروی کنند. به عنوان مثال، تمام مبلها با هر سبکی که دارند باید Interface مبل را پیاده سازی (implement) کنند؛ این روند به همین صورت باید برای محصولات دیگر انجام شود.
سپس باید در نرم افزار کارخانه ساخت محصولاتی را که از یک سبک هستند به صورت جداگانه تعریف شوند. برای این منظور نیاز به ایجاد یک Interface جدید خواهیم داشت که توابع و روش ساخت محصولات در آن تعریف میشوند. مثلا اگر نام کارخانه اصلی را کارخانه ساخت مبلمان در نظر گیریم، در این Interface توابع مربوط به ایجاد مبل، کاناپه و میز تعریف میشوند. همه این توابع باید یک محصول از نوع انتزاعی (Abstract) برگردانند. همچنین محصولاتی در این کارخانهها تولید میشوند باید همگی محصولاتی باشند که به صورت Interface تعریف شده اند: مثلا مبل، کاناپه و میز.
برای هر سبک از محصولات، باید یک کلاس کارخانه ساخته شود که از Interface کارخانه ساخت مبلمان پیروی میکند. بر این اساس هر کارخانه یک کلاس است که از یک interface برای دریافت توابع پیروی میکند و محصولاتی از یک نوع خاص را بر میگرداند. به عنوان مثال، کارخانه ساخت مبلمان مدرن تنها میتواند مبل مدرن، کاناپه مدرن و میز مدرن ایجاد کند.
نرم افزار باید به گونه ای طراحی شده باشد که حتما کارخانهها و محصولات از Interfaceها پیروی کنند. با این کار شما میتوانید بدون اینکه نیازی به تغییر در کدهای اصلی نرم افزار داشته باشید، به راحتی در کارخانه و محصولات تغییر ایجاد کنید. از طرفی دیگر با این کار هر محصولی که توسط مشتری سفارش داده میشود، همیشه از لحاظ سبک با یکدیگر سازگار خواهند بود و دیگر از بابت نامتناسب بودن آنها نگرانی نخواهد بود. زیرا کارخانهها از لحاظ سبک تولیدی از یکدیگر متمایز شده اند.
کاربردهای الگوی طراحی کارخانه انتزاعی
زمانی که کاربر به صورت دقیق از نوع شی ای که میخواهد ایجاد کند اطلاع نداشته باشد، از این دیزاین پترن استفاده میشود. همچنین اگر در آینده به امکان افزوده شدن محصولاتی جدید با سبکهای متفاوت وجود داشته باشد، به منظور جلوگیری از ایجاد تغییرات در کدهای نرم افزار و افزایش انعطاف پذیری آن از الگوی طراحی کارخانه انتزاعی استفاده میشود. این الگو 4 جز اصلی دارد که عبارتند از :
Abstract Factory : یک Interface است که ساختار کلی کلاسها را تعریف میکند.
Concrete Factory : کلاسی است که محصولات مربوط به یک سبک را تعریف میکند.
Abstract Product : کلاسی است که ساختار و توابع محصولات قابل تولید توسط کارخانه را تعریف میکند.
Product : محصولات هستند که توسط کارخانه تولید میشوند.
پیاده سازی الگوی طراحی کارخانه انتزاعی
در این بخش به بررسی مراحل پیاده سازی الگوی طراحی کارخانه انتزاعی میپردازیم، سپس با استفاده از زبان برنامه نویسی PHP این الگو را در قالب یک مثال پیاده سازی خواهیم کرد. مراحل پیاده سازی این الگو عبارتند از :
ابتدا باید لیستی از انواع اشیای مورد نظر در نرم افزار تهیه شود.
باید برای هر یک از انواع آنها یک Interface تعریف شود. سپس تمام کلاسهای این اشیا باید از این Interfaceها پیروی کنند.
در این گام Interface کارخانه انتزاعی باید ایجاد شود. در این Interface مجموعه ای از روشهای ایجاد اشیا انتزاعی تعریف میشود.
باید برای هر یک از اشیا که سبک مشابهی دارند کلاسهای به عنوان کارخانه سازنده آنها ایجاد شود. این کارخانهها که اشیا مرتبط را تولید میکنند باید از Interface کارخانه انتزاعی پیروی کنند.
کد مربوط به راه اندازی کارخانه را در نرم افزار باید نوشت. این کد باید یک کلاس کارخانه مرتبط را بسته باشد، بسته به پیکربندی برنامه یا محیط فعلی. این کارخانه را به کلیه کلاس هایی که محصولات را طراحی میکنند انتقال دهید.
هر جایی در کدهای نرم افزار که اشیا به صورت مستقیم ایجاد شده اند، باید شناسایی شود. سپس آنها با توابع ساخت مناسب با توجه به کارخانه مربوطه جایگزین شوند.
مثالی از الگوی طراحی کارخانه انتزاعی در دنیای واقعی
در این مثال، از الگوی کارخانه انتزاعی به منظور ایجاد یک کارخانه برای تولید انواع قالبهای مختلف برای عناصر مختلف یک صفحه وب استفاده میشود. زیرا یک وبسایت قادر است از موتورهای رندر مختلف به صورت همزمان پشتیبانی کند. به دلیل تفاوت در کدهای مربوط به هر یک از موتورهای رندر قالب، ایجاد Templateها باید توسط کارخانه اختصاصی خود انجام شوند.
?php
/**
* The Abstract Factory interface declares creation methods for each distinct
* product type.
*/
interface TemplateFactory
{
public function createTitleTemplate(): TitleTemplate;
public function createPageTemplate(): PageTemplate;
}
/**
* Each Concrete Factory corresponds to a specific variant (or family) of
* products.
*
* This Concrete Factory creates Twig templates.
*/
class TwigTemplateFactory implements TemplateFactory
{
public function createTitleTemplate(): TitleTemplate
{
return new TwigTitleTemplate;
}
public function createPageTemplate(): PageTemplate
{
return new TwigPageTemplate($this->createTitleTemplate());
}
}
/**
* And this Concrete Factory creates PHPTemplate templates.
*/
class PHPTemplateFactory implements TemplateFactory
{
public function createTitleTemplate(): TitleTemplate
{
return new PHPTemplateTitleTemplate;
}
public function createPageTemplate(): PageTemplate
{
return new PHPTemplatePageTemplate($this->createTitleTemplate());
}
}
/**
* Each distinct product type should have a separate interface. All variants of
* the product must follow the same interface.
*
* For instance, this Abstract Product interface describes the behavior of page
* title templates.
*/
interface TitleTemplate
{
public function getTemplateString(): string;
}
/**
* This Concrete Product provides Twig page title templates.
*/
class TwigTitleTemplate implements TitleTemplate
{
public function getTemplateString(): string
{
return "<h1></h1>";
}
}
/**
* And this Concrete Product provides PHPTemplate page title templates.
*/
class PHPTemplateTitleTemplate implements TitleTemplate
{
public function getTemplateString(): string
{
return "<h1><?= \$title; ?></h1>";
}
}
/**
* This is another Abstract Product type, which describes whole page templates.
*/
interface PageTemplate
{
public function getTemplateString(): string;
}
/**
* The page template uses the title sub-template, so we have to provide the way
* to set it in the sub-template object. The abstract factory will link the page
* template with a title template of the same variant.
*/
abstract class BasePageTemplate implements PageTemplate
{
protected $titleTemplate;
public function __construct(TitleTemplate $titleTemplate)
{
$this->titleTemplate = $titleTemplate;
}
}
/**
* The Twig variant of the whole page templates.
*/
class TwigPageTemplate extends BasePageTemplate
{
public function getTemplateString(): string
{
$renderedTitle = $this->titleTemplate->getTemplateString();
return <<<HTML
<div class="page">
$renderedTitle
<article class="content"></article>
</div>
HTML;
}
}
/**
* The PHPTemplate variant of the whole page templates.
*/
class PHPTemplatePageTemplate extends BasePageTemplate
{
public function getTemplateString(): string
{
$renderedTitle = $this->titleTemplate->getTemplateString();
return <<<HTML
<div class="page">
$renderedTitle
<article class="content"><?= \$content; ?></article>
</div>
HTML;
}
}
/**
* The client code. Note that it accepts the Abstract Factory class as the
* parameter, which allows the client to work with any concrete factory type.
*/
function templateRenderer(TemplateFactory $factory)
{
$pageTemplate = $factory->createPageTemplate();
echo $pageTemplate->getTemplateString();
// Here's how would you use the template further in real life:
// Twig::render($pageTemplate->getTemplateString(), [
// 'title' => $page->title,
// 'content' => $page->content, ]);
}
/**
* Now, in other parts of the app, the client code can accept factory objects of
* any type.
*/
echo "Testing rendering with the Twig factory:\n";
templateRenderer(new TwigTemplateFactory);
echo "\n\n";
echo "Testing rendering with the PHPTemplate factory:\n";
templateRenderer(new PHPTemplateFactory);
اگر میخواهید بیشتر راجب الگوهای طراحی بدانید, مقالات زیر را مطالعه کنید
الگوی کارخانه انتزاعی جزو دیزاین پترنهای پر استفاده در برنامه نویسی است. بسیاری از فریم ورکها و کتابخانهها از این روش برای ارائه راه حلی برای گسترش و سفارشی کردن اجزای خود استفاده میکنند. البته استفاده از این الگوی طراحی ممکن است باعث پیچیده شدن فرآیند کدنویسی شود. زیرا در این الگو از Interfaceها و کلاسهای جدیدی زیادی استفاده میشود. به نظر شما استفاده از این الگوی طراحی در چه نرم نوع افزارهایی نیاز میشود؟
۵ دیدگاه
۲۷ اسفند ۱۴۰۱، ۱۶:۳۲
مقاله خیلی خوبی بود. فقط کاشکی ترجمه کردین منبع هم میزدین.
۲۵ بهمن ۱۴۰۰، ۲۳:۴۲
عالی
Mohammad H۱۱ آبان ۱۳۹۹، ۱۱:۵۵
تفاوت این الگو با الگوی استراتژی در چیه؟
نازنین کریمی مقدم۱۲ آبان ۱۳۹۹، ۱۱:۳۵
درود خداوند. سوال خیلی خوبی پرسیدید:)
الگوی فکتوری بیشتر برای ساختار به کار میره، یعنی با استفاده از اون ما کلاسهای متفاوت تعریف میکنیم. اما الگوی استراتژی بیشتر عملیاتیه و براساس فانکشن به کار میره.
یه مثال واضح میزنم که تفاوت شون رو بهتر متوجه بشید:
فرض کنید شما یه کلاس کارخانه مواد غذایی دارید. با استفاده از الگوی فکتوری این کارخانه رو براساس نوع محصول به بخشهای مختلف مثل کارخانه نوشابه سازی، کارخانه غذاهای منجمد و ... تقسیم میکنید.
حالا هر کارخانه ای ممکن هست که در بخش ارسال به فروشگاهها دارای روشهای مختلفی مثل ارسال با کشتی، ارسال با کامیون، ارسال با قطار و ... باشه. این روشها رو در قالب الگوی استراتژی پیاده سازی میکنید.
همونطور که در مثال دیدید این دو الگو میتونند با هم استفاده شوند و مشکلی هم به وجود نمیاد. امیدوارم تونسته باشم تفاوتشون رو به صورت واضح شرح بدم.
hamidreza۲۳ اردیبهشت ۱۳۹۸، ۱۳:۳۵
خیلی کامل بود جالب بود!
شروع رایگان یادگیری برنامه نویسی
کلیک کنید 👇
دوره الفبای برنامه نویسی با هدف انتخاب زبان برنامه نویسی مناسب برای شما و پاسخگویی به سوالات متداول در شروع یادگیری موقتا رایگان شد: