الگوی Factory در C#: ایجاد اشیای انعطافپذیر
چرا به Factory Pattern نیاز داریم؟
در برنامهنویسی شیگرا، اغلب نیاز داریم که اشیایی از انواع مختلف را ایجاد کنیم. اگر کد ایجاد این اشیا (معمولاً با استفاده از عملگر new) به طور مستقیم در کلاسی که از آنها استفاده میکند، جاسازی شود، آن کلاس به طور محکمی به پیادهسازیهای خاص آن اشیا وابسته میشود. این وابستگی محکم (Tight Coupling) مشکلات زیر را ایجاد میکند:
-
کاهش انعطافپذیری: اگر بخواهیم نوع شیء ایجاد شده را تغییر دهیم (مثلاً از SqlServerConnection به OracleConnection برویم)، باید کدی را که از آن استفاده میکند، دستکاری کنیم.
-
سختتر شدن نگهداری: معرفی یک نوع شیء جدید (مثلاً PostgresConnection) مستلزم تغییر در بسیاری از قسمتهای کد است.
-
نقض اصل باز-بسته (Open/Closed Principle - OCP): اصل OCP بیان میکند که یک موجودیت نرمافزاری باید برای توسعه باز باشد اما برای تغییر بسته باشد. وابستگی محکم، این اصل را نقض میکند.
الگوی Factory Pattern با پنهان کردن منطق ایجاد شیء و انتزاع فرآیند ساخت، این مشکلات را حل میکند.
انواع Factory Pattern
الگوی Factory در عمل در دو شکل اصلی ظاهر میشود که هر دو به هدف اصلی (ایجاد اشیا بدون افشای منطق ساخت) خدمت میکنند، اما در سطح انتزاع متفاوت هستند:
1. Factory Method (متد کارخانه)
Factory Method یک الگوی ایجادگر (Creational) است که در آن یک متد (معمولاً با نامی مانند Create یا FactoryMethod) در یک رابط (Interface) یا کلاس پایه (Base Class) تعریف میشود، اما پیادهسازی واقعی آن به کلاسهای فرعی (Subclasses) واگذار میشود.
-
هدف: اجازه دادن به کلاسهای فرعی برای تصمیمگیری در مورد اینکه کدام کلاس را نمونهسازی کنند.
-
مثال رایج: در یک بازی که چندین نوع شخصیت (مثلاً جادوگر، جنگجو) دارد، کلاس پایه CharacterCreator میتواند متد CreateCharacter را تعریف کند، در حالی که MageCreator و WarriorCreator نحوه ساخت شخصیتهای خاص خود را پیادهسازی میکنند.
2. Abstract Factory (کارخانه انتزاعی)
Abstract Factory سطح بالاتری از انتزاع است که یک واسط برای ایجاد خانوادههایی از اشیا مرتبط یا وابسته به هم را بدون تعیین کلاسهای بتنی (Concrete Classes) آنها فراهم میکند.
-
هدف: ارائه یک کیت ابزار برای ایجاد مجموعهای از محصولات مرتبط.
-
مثال رایج: فرض کنید سیستمی برای طراحی رابط کاربری برای دو سیستم عامل (Windows و macOS) دارید. GUIFactory یک کارخانه انتزاعی خواهد بود که متدهایی مانند CreateButton() و CreateCheckBox() را تعریف میکند. سپس، WindowsFactory اشیای دکمه و چکباکس با ظاهر Windows و MacFactory اشیای با ظاهر Mac را ایجاد میکند.
در این مقاله، تمرکز اصلی بر روی پیادهسازی رایجتر و سادهتر، یعنی Factory Method و یک پیادهسازی سادهشده از آن در قالب Simple Factory خواهد بود.
پیادهسازی Simple Factory در #C
Simple Factory (که از نظر فنی یک الگوی طراحی گانگآففور نیست اما بسیار پرکاربرد است) سادهترین راه برای متمرکز کردن منطق ایجاد شیء است. در این رویکرد، ما یک کلاس کارخانه واحد داریم که مسئول ایجاد نمونههایی از کلاسهای دیگر است.
فرض کنید یک برنامه مدیریت اسناد داریم که میتواند فایلهایی از نوع PDF و Word را پردازش کند.
1. تعریف رابط محصول (Product Interface)
ابتدا یک رابط برای محصولات (اشیاء تولید شده) تعریف میکنیم:
// IProduct.cs
public interface IDocument
{
void Open();
void Save();
}
2. تعریف محصولات بتنی (Concrete Products)
سپس کلاسهایی که این رابط را پیادهسازی میکنند، ایجاد میکنیم:
// PdfDocument.cs
public class PdfDocument : IDocument
{
public void Open()
{
Console.WriteLine("Opening PDF document.");
}
public void Save()
{
Console.WriteLine("Saving PDF document.");
}
}
// WordDocument.cs
public class WordDocument : IDocument
{
public void Open()
{
Console.WriteLine("Opening Word document.");
}
public void Save()
{
Console.WriteLine("Saving Word document.");
}
}
3. پیادهسازی کلاس Simple Factory
اکنون، کلاس کارخانه را تعریف میکنیم که بر اساس یک ورودی (مثلاً یک رشته)، نمونه مناسب را برمیگرداند:
// DocumentFactory.cs
public static class DocumentFactory
{
public static IDocument CreateDocument(string documentType)
{
switch (documentType.ToLower())
{
case "pdf":
return new PdfDocument();
case "word":
return new WordDocument();
// اضافه کردن انواع جدید آسان است
case "excel":
return new ExcelDocument();
default:
throw new ArgumentException("Invalid document type.", nameof(documentType));
}
}
}
4. استفاده از Factory در کد کلاینت
کد کلاینت (کلاسی که از اشیا استفاده میکند) دیگر نیازی به دانستن جزئیات ساخت new PdfDocument() یا new WordDocument() ندارد. این کد فقط با رابط IDocument کار میکند:
// Program.cs
public class Application
{
public static void Main()
{
// کلاینت فقط از Factory استفاده می کند و با IDocument کار می کند
IDocument pdfDoc = DocumentFactory.CreateDocument("pdf");
pdfDoc.Open();
IDocument wordDoc = DocumentFactory.CreateDocument("word");
wordDoc.Save();
}
}
مزایای Factory Pattern
استفاده از الگوی Factory Pattern در C# چندین مزیت کلیدی برای توسعه نرمافزار به همراه دارد:

1. کاهش وابستگی (Decoupling)
مهمترین مزیت، کاهش وابستگی محکم بین کلاس کلاینت و کلاسهای محصول بتنی است. کلاس کلاینت فقط به رابط IDocument و متد استاتیک CreateDocument در DocumentFactory وابسته است، نه به پیادهسازیهای خاص (مانند PdfDocument). این کار باعث میشود که تغییر یک پیادهسازی بر سایر بخشهای کد تأثیر نگذارد.
2. اصل OCP (Open/Closed Principle)
Factory Pattern به طور کامل اصل OCP را محقق میکند. اگر بخواهید یک نوع سند جدید (مثلاً ExcelDocument) اضافه کنید، تنها کافی است:
-
کلاس ExcelDocument را پیادهسازی کنید.
-
کد کوچکی را در متد CreateDocument در DocumentFactory اضافه کنید.
کلاسهای کلاینت که از کارخانه استفاده میکنند، بدون تغییر باقی میمانند (بسته برای تغییر) و سیستم برای پذیرش انواع جدید (باز برای توسعه) آماده است.
3. متمرکزسازی منطق ایجاد شیء
منطق پیچیده مربوط به نحوه، زمان و شرایط ایجاد یک شیء، در یک مکان واحد (کلاس کارخانه) متمرکز میشود. این امر خوانایی، تستپذیری و دیباگ کردن کد را بسیار سادهتر میکند. اگر فرآیند ساخت یک شیء شامل تنظیمات اولیه یا تزریق وابستگیهای پیچیدهای باشد، این تمرکز اهمیت دوچندانی پیدا میکند.
4. تستپذیری بهتر
با استفاده از Factory، میتوانید اشیای ساختگی (Mock Objects) یا نمونههای تست (Test Doubles) را در زمان اجرای تست تزریق کنید. به جای نمونهسازی یک شیء سنگین یا وابسته به منابع خارجی (مانند اتصال به پایگاه داده)، Factory میتواند در محیط تست، یک شیء سادهشده و قابل کنترل را برگرداند.
محدودیتها و ملاحظات Factory Pattern
هیچ الگوی طراحی بدون محدودیت نیست. در حالی که Factory Pattern قدرت زیادی دارد، باید در موارد مناسب استفاده شود:
-
پیچیدگی اولیه: برای پروژههای کوچک و ساده که تنها یک یا دو نوع شیء ایجاد میشود، معرفی یک کلاس کارخانه میتواند سربار غیرضروری ایجاد کند. باید بین انعطافپذیری آینده و پیچیدگی فعلی تعادل برقرار کرد.
-
رشد کلاسهای کارخانه: در پیادهسازی Simple Factory، اگر تعداد انواع محصول بسیار زیاد شود، متد CreateDocument میتواند بسیار بزرگ و پر از دستورات switch یا if/else شود. در این حالت، باید به سراغ Factory Method یا Abstract Factory رفت تا وظیفه ساخت به کلاسهای فرعی تقسیم شود.
نتیجهگیری
الگوی Factory Pattern یکی از ابزارهای حیاتی در جعبه ابزار هر توسعهدهنده C# است. این الگو نه تنها راهی منظم و سازمانیافته برای ایجاد اشیا فراهم میکند، بلکه با حذف وابستگیهای محکم و تمرکز بر واسطها به جای پیادهسازیها، به طور مستقیم به اصول اساسی برنامهنویسی شیگرا و توسعه نرمافزارهای پایدار کمک میکند. با استفاده از Factory، سیستمهای شما انعطافپذیرتر میشوند، به طوری که توسعه و نگهداری آنها در طول چرخه حیات محصول، آسانتر و کمخطرتر خواهد بود.
0 نظر
هنوز نظری برای این مقاله ثبت نشده است.