post image
Design Patterns

الگوی طراحـــــــــی Abstract Factory

learnabstract factorycsharp

دیزاین پترن ها در کنار تمرکز بر حل مشکلات برنامه نویسی شی گرا، اهداف متفاوتی را دنبال می‌کنند. یکی از اهداف اصلی آن ها، افزایش خوانایی کدها و کاهش میزان کدنویسی است. الگوی طراحی کارخانه انتزاعی یا Abstract Factory جزو الگوهای طراحی سازنده (Creational) است که برای مدیریت ساخت اشیا از کلاس‌ها توسعه داده شده است. این الگوی طراحی به شما اجازه می‌دهد که مجموعه ای از اشیا مرتبط را بدون نیاز به ساخت کلاس‌های جداگانه و متعدد ایجاد کنید.

فرض کنیم که یک سری ui-element داریم. اپلیکیشنی هم داریم که cross platform هست. کامپوننت هایی که طراحی کردیم بر روی هرنوع سیستم عاملی دیده میشوند اما با اندکی تغییر در ظاهرشون. برای مثال ما برنامه تلگرام رو نوشتیم.
تلگرام بروی IOS,Android,Windows,macOs به یک شکل دیده میشود و نحوه عملکرد آن کاملا یکسان است. فقط برخی shortcut ها متفاوت عمل میکنند.
مثلا در محیط ویندوز ما با ctrl+k در برنامه مون میتونیم سرچ کنیم ولی در macOs با k+  میتونیم این عملرو انجام بدیم.
این وظیفه ما به عنوان برنامه نویس است که عملکرد برنامه مان در تمام سیستم عامل ها به یک شکل باشد. خب حالا بریم سراغ یک توضیح جامع در مورد کدی که میخواهیم بنویسیم و شیوه عملکرد اپلیکیشن مون:
موقعی که برنامه اجرا میشود، ابتدا میره نوع سیستم عامل رو چک میکنه. برنامه از این اطلاعات استفاده میکند تا یک شی از factory بسازه که مچه با اون سیستم عامل. بقیه کد هم از این شی استفاده میکنن برای ساختن ui elementهای مخصوص اون سیستم عامل. اینکار از ساختن ui elementهای اشتباه در برنامه جلوگیری میکنه. (انگار شما وارد یه تونل میشین که فقط روبروتون میبینین و کاری به کنارتون ندارین.)
با این قابلیت client code به یک کلاس خاص وابسته نیست. همچنین این کمک میکنه که client code باقی کلاس های که جزو factory هستند و از اون ارث بری کردند رو هم ساپورت کنه و میتونیم ui element های بیشتری رو به پروژه اضافه کنیم.
دیگه نیازی نیست هر وقت که یک ui element جدید اضافه کردین به برنامه تون دوباره client code رو modify کنیم و کاستوم کنین برای المنت های جدید.
شما فقط یک کار باید انجام بدین:
کلاس کارخانه جدید ایجاد کنید که این عناصر رو تولید کنه و کمی کد اولیه برنامه را تغییر دهید تا در صورت لزوم اون کلاس را انتخاب کنه.
از Abstract Factory زمانی استفاده کنید که کد شما باید با خانواده‌های مختلف محصولات مرتبط کار کنید، اما نمی‌خواهید به کلاس‌های مشخص آن محصولات، بستگی داشته باشید. ممکن است از قبل ناشناخته باشند یا فقط بخواهید امکان توسعه‌پذیری در آینده را فراهم کنید.
Abstract Factory یک رابط برای ایجاد اشیاء از هر کلاس از خانواده محصول در اختیار شما قرار می دهد. تا زمانی که کد شما اشیاء را از طریق این رابط ایجاد می کنید، لازم نیست نگران ایجاد نوع اشتباه محصول باشید. در یک برنامه خوب طراحی شده، هر کلاس فقط مسئول یک چیز است.

Relation with other patterns

  • بسیاری از طراحی ها با استفاده از روش Factory (کمتر پیچیده و قابل تنظیم تر از طریق زیر کلاس ها) شروع می شوند و به سمت Abstract Factory، Prototype یا Builder (انعطاف پذیرتر، اما پیچیده تر) تکامل می یابند.

  • builder بر ساختن اشیاء پیچیده گام به گام تمرکز می کند. Abstract Factory در ایجاد خانواده از اشیاء مرتبط تخصص دارد. Abstract Factory محصول را فوراً برمی گرداند، در حالی که Builder به شما امکان می دهد قبل از واکشی محصول، مراحل ساخت و ساز اضافی را اجرا کنید.

  • Abstract factory classes اغلب بر اساس مجموعه ای از Factory Method ها هستند، اما شما همچنین می توانید از Prototype برای ترکیب متدهای این کلاس ها استفاده کنید.

  • Abstract Factory می تواند به عنوان جایگزینی برای Facade عمل کند که شما فقط می خواهید نحوه ایجاد اشیاء زیرسیستم را از client code پنهان کنید.

  • می توانید از Abstract Factory در کنار Bridge استفاده کنید. این جفت شدن زمانی مفید است که برخی از abstraction های تعریف شده توسط Bridge فقط می توانند با پیاده سازی های خاص کار کنند. در این مورد، Abstract Factory می تواند این روابط را کپسوله کند و پیچیدگی را از client code پنهان کند.

  • Abstract Factory، Builders و Prototypes همگی می‌توانند به‌عنوان Singletons پیاده‌سازی شوند.

برای جا افتادن این مطلب ما سعی داریم در این وبلاگ یک مثال از دنیای واقعی (real world example) براتون بزنیم.


namespace RealWorldExamples.src.creational.AbstractFactory
{
    // The Abstract Factory interface declares a set of methods that return
    // different abstract products. These products are called a family and are
    // related by a high-level theme or concept. Products of one family are
    // usually able to collaborate among themselves. A family of products may
    // have several variants, but the products of one variant are incompatible
    // with products of another.
    public interface IGUIFactory
    {
        IButton Button();

        ICheckbox Checkbox();
    }

    // Concrete Factories produce a family of products that belong to a single
    // variant. The factory guarantees that resulting products are compatible.
    // Note that signatures of the Concrete Factory's methods return an abstract
    // product, while inside the method a concrete product is instantiated.
    class WinFactory : IGUIFactory
    {
        public IButton Button()
        {
            return new WinButton();
        }

        public ICheckbox Checkbox()
        {
            return new WinCheckbox();
        }
    }

    // Each Concrete Factory has a corresponding product variant.
    class MacFactory : IGUIFactory
    {
        public IButton Button()
        {
            return new MacButton();
        }

        public ICheckbox Checkbox()
        {
            return new MacCheckbox();
        }
    }

    // Each distinct product of a product family should have a base interface.
    // All variants of the product must implement this interface.
    public interface IButton
    {
        string UsefulFunctionA();
    }

    // Concrete Products are created by corresponding Concrete Factories.
    class WinButton : IButton
    {
        public string UsefulFunctionA()
        {
            return "The result of the product A1.";
        }
    }

    class MacButton : IButton
    {
        public string UsefulFunctionA()
        {
            return "The result of the product A2.";
        }
    }

    // Here's the the base interface of another product. All products can
    // interact with each other, but proper interaction is possible only between
    // products of the same concrete variant.
    public interface ICheckbox
    {
        // Product B is able to do its own thing...
        string UsefulFunctionB();

        // ...but it also can collaborate with the ProductA.
        //
        // The Abstract Factory makes sure that all products it creates are of
        // the same variant and thus, compatible.
        string AnotherUsefulFunctionB(IButton collaborator);
    }

    // Concrete Products are created by corresponding Concrete Factories.
    class WinCheckbox : ICheckbox
    {
        public string UsefulFunctionB()
        {
            return "The result of the product B1.";
        }

        // The variant, Product B1, is only able to work correctly with the
        // variant, Product A1. Nevertheless, it accepts any instance of
        // AbstractProductA as an argument.
        public string AnotherUsefulFunctionB(IButton collaborator)
        {
            var result = collaborator.UsefulFunctionA();

            return $"The result of the B1 collaborating with the ({result})";
        }
    }

    class MacCheckbox : ICheckbox
    {
        public string UsefulFunctionB()
        {
            return "The result of the product B2.";
        }

        // The variant, Product B2, is only able to work correctly with the
        // variant, Product A2. Nevertheless, it accepts any instance of
        // AbstractProductA as an argument.
        public string AnotherUsefulFunctionB(IButton collaborator)
        {
            var result = collaborator.UsefulFunctionA();

            return $"The result of the B2 collaborating with the ({result})";
        }
    }

    // The client code works with factories and products only through abstract
    // types: AbstractFactory and AbstractProduct. This lets you pass any
    // factory or product subclass to the client code without breaking it.
    class Client
    {
        public void Main()
        {
            // The client code can work with any concrete factory class.
            Console.WriteLine("Client: Testing client code with the first factory type...");
            ClientMethod(new WinFactory());
            Console.WriteLine();

            Console.WriteLine("Client: Testing the same client code with the second factory type...");
            ClientMethod(new MacFactory());
        }

        public void ClientMethod(IGUIFactory factory)
        {
            var productA = factory.Button();
            var productB = factory.Checkbox();

            Console.WriteLine(productB.UsefulFunctionB());
            Console.WriteLine(productB.AnotherUsefulFunctionB(productA));
        }
    }

    class RunAbstractFactoryProgram
    {
        public static void Main()
        {
            new Client().Main();
        }
    }
}
    
icon drow down
خدمات ما
پروژه های اخیر
طراحی ست اداری شرکت hydout
طراحی Low Poly زومجی
طراحی UI/UX شرکت Rainbow
طراحی ست اداری شرکت hydout
طراحی ست اداری شرکت hydout
طراحی ست اداری شرکت hydout
طراحی ست اداری شرکت hydout
طراحی ست اداری شرکت hydout
طراحی ست اداری شرکت hydout
طراحی ست اداری شرکت hydout
طراحی ست اداری شرکت hydout
طراحی ست اداری شرکت hydout

پروژه جدید داری؟