الگوهای برنامه نویسی (abstract factory)

بسم الله الرحمن الرحیم

بخش ششم

الگوهای برنامه نویسی

الگوی Abstract Factory

در آموزش قبل با روش Method Factory آشنا شدیم، در این روش با الگوی برنامه نویسی Abstract Factory آشنا خواهیم شد.

در روش Method Factory تمامی اشیا توسط یک متد ایجاد می شدند، اما در روش Abstract Factory هر کلاس یک سازنده جداگانه خواهد داشت و البته همه ی این سازنده ها در کلاس اصلی ما قرار می گیرند.

آموزش Method Factory

در Abstract Factory ما یک Interface اصلی خواهیم داشت که مجموعه ای از Object های وابسته را تعریف می کند. در Abstract Factory ما وظیفه ی تولید هر شی را به Factory مربوطه اش واگذار می کنیم، اینجاست که اگر بعد از مدتی از ما خواسته شود که برنامه را بسط بدهیم تنها با ایجاد یک Factory مشکل را می توانیم حل می کنیم.

روش Abstract Factory برای ایجاد اشیای مرتبط مورد استفاده قرار می گیرد، این روش به دلیل اینکه تمامی اشیا را به صورت واحد طراحی و ایجاد می کند روش Factory of factories نیز خوانده می شود، همانطور که گفته شد در روش Abstract Factory یک interface مسئولیت ایجاد و ساخت اشیاء مرتبط را به عهده دارد.

بر اساس تصویر بالا یک برنامه طراحی شده با استفاده از AbstractFactory دارای 5 قسمت خواهد بود:

AbstractFactory

یک interface می باشد که برای ساخت abstract product مورد استفاده قرار می گیرد.

ConcreteFactory

کلاسی که اینترفیس AbstractFactory را برای concrete products پیاده سازی می کند.

AbstractProduct

AbstractProduct یک interface است که اشیا (product های) ما را تعریف می کند.

ConcreteProduct

ConcreteProduct یک کلاس است که اینترفیس AbstractProduct را برای ساخت  اشیا (product های) پیاده سازی می کند.

Client

Client یک کلاس است که از اینترفیس AbstractFactory و AbstractProduct برای ساخت اشیاء مرتبط استفاده می کند.

برای درک بهتر این مباحث مثالی را با هم بررسی خواهیم کرد.

فرض کنید قرار است یک فروشگاه فروش لوازم کامپیوتری ایجاد کنیم، درخت ارتباط بین کلاس ها به صورت زیر می باشد:

کل کدهای این پروژه را ابتدا از بخش زیر دانلود کنید و سپس این مقاله را ادامه دهید.

دانلود پروژه ی Abstract factory

پروژه مربوطه را باز کنید و کلاس های آن را بررسی کنید، هر یک از کلاس های این پروژه وظایف خاصی دارند که می توان این وظایف را به صورت زیر تعریف کرد.

بر اساس تصویر بالا هر یک از بخش های AbstractFactory ما به صورت زیر خواهد بود.

در این مثال AbstractFactory ما IMachineFactory است.

همچنین Concreate Product های ما کلاس های بخش Budget هستند.

AbstractProduct ما، اینترفیس های IHardDisk، IMonitor و IProcessor هستند.

بخش Concrete Factories ما شامل کلاس های Cheap, Expensive و High, Low می باشد.

درنهایت بخش Client ما کدهای ComputerShop ما می باشد.

همانطور که در تصویر بالا مشاهده می کنید ما سه interface با نام های IHardDisk، IMonitor و IProcessor داریم. این interface ها هر کدام تنها یک متد ساده خواهند داشت تا مفاهیم را به خوبی انتقال دهند، متدها فقط یک متن را چاپ خواهند کرد.

کدهای این اینترفیس ها به صورت زیر می باشد.

public interface IHardDisk { 
void StoreData();
}

public interface IMonitor {
void DisplayPicture();
}

public interface IProcessor
{
void PerformOperation();
}

حال ما از روی هر یک از این interface ها کلاس های خود را ایجاد می کنیم، در بدنه ی هر یک از این کلاس ها، همان متن پیام ما نوشته می شود.

برای نمونه اگر کد یکی از این کلاس ها را بخواهیم بررسی کنیم،کد ما به صورت زیر خواهد بود. همانطور که مشاهده می کنید کلاس ما از IHardDisk ارث برده است و متد IHardDisk را پیاده سازی کرده است.

public class ExpensiveHDD : IHardDisk
{
public void StoreData()
{
Console.WriteLine("Data will take less time to store");
}
}

تا اینجا تصور می کنیم ما یک برنامه ی کامل داریم، که برنامه ی ما Interface هایی دارد که این Interface ها توسط کلاس هایی ارث بری شده اند و این کلاس ها متدهای Interface خود را پیاده سازی کرده اند.

کار اصلی ما از این قسمت شروع خواهد شد، برای استفاده از interface های طراحی شده در مرحله ی قبل کافی است یک interface جدید تعریف کنیم که این interface از هر یک از interface های مرحله ی قبل  instance ایی را ایجاد می کند. کد ما به صورت زیر خواهد بود.

اینترفیس IMachineFactory به صورت زیر پیاده می کنیم:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AbstractFactory.Shop
{
    public interface IMachineFactory
    {
        IProcessor GetRam();
        IHardDisk GetHardDisk();
        IMonitor GetMonitor();
    }
}

در پوشه Budget نیز سه کلاس به صورت زیر تعریف شده است:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AbstractFactory.Shop
{
    public class HighBudgetMachine : IMachineFactory
    {
        public IProcessor GetRam() { return new ExpensiveProcessor(); }
        public IHardDisk GetHardDisk() { return new ExpensiveHDD(); }
        public IMonitor GetMonitor() { return new HighResolutionMonitor(); }
    }
}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AbstractFactory.Shop
{
    public class AverageBudgetMachine : LowBudgetMachine
    {
        public override IProcessor GetRam()
        {
            return new ExpensiveProcessor();
        }
    }
}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AbstractFactory.Shop
{
    public class LowBudgetMachine : IMachineFactory
    {
        public virtual IProcessor GetRam() { return new CheapProcessor(); }
        public IHardDisk GetHardDisk() { return new CheapHDD(); }
        public IMonitor GetMonitor() { return new LowResolutionMonitor(); }
    }
}

همانطور که مشاهده می کنید کدهای بالا بسیار ساده و مشخص هستند. در کلاس های پوشه budget ما ابتدا از اینترفیس IMachineFactory ارث برده ایم و همچنین سه متد اینترفیس IMachineFactory را پیاده سازی کرده ایم که هر یک از این متد ها یک instance از کلاس مربوطه باز می گرداند. 

در نهایت وقتی بخواهیم از اینترفیس خود یعنی همان اینترفیس IMachineFactory استفاده کنیم، کافی است کلاسی به صورت زیر داشته باشیم. ما نام این کلاس را ComputerShop قرارداده ایم که کد آن به صورت زیر می باشد:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AbstractFactory.Shop
{
    public class ComputerShop
    {
        IMachineFactory category;
        public ComputerShop(IMachineFactory _category)
        {
            category = _category;
        }
        public void AssembleMachine()
        {
            IProcessor processor = category.GetRam();
            IHardDisk hdd = category.GetHardDisk();
            IMonitor monitor = category.GetMonitor();

            processor.PerformOperation();
            hdd.StoreData();
            monitor.DisplayPicture();
        }
    }
}

حال کافی است در برنامه خود، کلاس Main به شکل زیر عمل کنیم.

using AbstractFactory.Shop;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AbstractFactory
{
    class Program
    {
        static void Main(string[] args)
        {
          
            IMachineFactory factory = new AverageBudgetMachine();/* Or new LowBudgetMachine(); */
            ComputerShop shop = new ComputerShop(factory);
            shop.AssembleMachine();


            Console.ReadLine();
        }
    }
}

تفاوت های Factory Method با Abstract Factory

  • Factory Method تنها برای ایجاد یک محصول است اما Abstract Factory می تواند چندین محصول مرتبط را هم ایجاد کند.
  • امکان بسط پروژه در حالت استفاده از Abstract Factory بسیار راحت تر می باشد.

همانطور که مشاهده کردید کار و فعالیت های مربوط به ساخت اشیا در الگوی Abstract Factory توسط اینترفیس های خاصی انجام می شود و شما می توانید به سادگی بخش های مختلف برنامه خود را توسعه و رشد دهید.

در آموزش بعد با الگوی Singleton آشنا خواهیم شد.

نظرات (۱)

ممنون کامل و خوب بود
ارسال نظر آزاد است، اما اگر قبلا در بیان ثبت نام کرده اید می توانید ابتدا وارد شوید.
شما میتوانید از این تگهای html استفاده کنید:
<b> یا <strong>، <em> یا <i>، <u>، <strike> یا <s>، <sup>، <sub>، <blockquote>، <code>، <pre>، <hr>، <br>، <p>، <a href="" title="">، <span style="">، <div align="">
تجدید کد امنیتی