JavaRush /وبلاگ جاوا /Random-FA /الگوهای طراحی: AbstractFactory

الگوهای طراحی: AbstractFactory

در گروه منتشر شد
سلام! امروز ما به مطالعه الگوهای طراحی و صحبت در مورد کارخانه انتزاعی ادامه خواهیم داد . الگوهای طراحی: AbstractFactory - 1آنچه در طول سخنرانی انجام خواهیم داد:
  • بیایید بحث کنیم که یک کارخانه انتزاعی چیست و این الگو چه مشکلی را حل می کند.
  • ما چارچوب یک برنامه کاربردی بین پلتفرمی را برای سفارش قهوه با رابط کاربری ایجاد خواهیم کرد.
  • بیایید دستورالعمل استفاده از این الگو را با نمودار و کد مطالعه کنیم.
  • به عنوان یک جایزه، یک تخم مرغ عید پاک در سخنرانی پنهان شده است که به لطف آن یاد خواهید گرفت که نام سیستم عامل را با استفاده از جاوا تعیین کنید و بسته به نتیجه، یک یا عمل دیگری را انجام دهید.
برای درک کامل این الگو، باید درک خوبی از موضوعات زیر داشته باشید:
  • وراثت در جاوا؛
  • کلاس ها و متدهای انتزاعی در جاوا

الگوی انتزاعی کارخانه چه مشکلاتی را حل می کند؟

کارخانه انتزاعی، مانند تمام الگوهای کارخانه، به ما کمک می کند تا خلق اشیاء جدید را به درستی سازماندهی کنیم. با کمک آن، ما "آزادسازی" خانواده های مختلف اشیاء به هم پیوسته را مدیریت می کنیم. خانواده های مختلف اشیاء مرتبط با یکدیگر ... چیست؟ نگران نباشید: در عمل همه چیز ساده تر از چیزی است که به نظر می رسد. بیایید با خانواده ای از اشیاء مرتبط شروع کنیم؟ فرض کنید ما در حال توسعه یک استراتژی با شما هستیم و چندین واحد رزمی در آن وجود دارد:
  • پیاده نظام؛
  • سواره نظام؛
  • کمانداران
این نوع یگان های رزمی با یکدیگر مرتبط هستند، زیرا در یک ارتش خدمت می کنند. می توان گفت که دسته بندی های ذکر شده در بالا خانواده ای از اشیاء مرتبط با یکدیگر هستند. که مرتب شده است. اما الگوی کارخانه انتزاعی برای سازماندهی ایجاد خانواده های مختلف از اشیاء به هم پیوسته استفاده می شود. اینجا هم هیچ چیز پیچیده ای نیست. بیایید مثال را با استراتژی ادامه دهیم. آنها معمولاً چندین طرف متضاد مختلف دارند. واحدهای رزمی طرف های مختلف ممکن است از نظر ظاهری تفاوت های چشمگیری داشته باشند. سربازان پیاده، سوارکاران و کمانداران ارتش روم با سربازان پیاده، سوارکاران و کمانداران وایکینگ ها یکی نیستند. در چارچوب استراتژی، سربازان ارتش های مختلف خانواده های مختلفی از اشیاء به هم پیوسته هستند. خنده دار خواهد بود اگر به اشتباه یک برنامه نویس، سربازی با لباس فرانسوی از زمان ناپلئون، با یک تفنگ آماده، در میان پیاده نظام رومی قدم می زد. برای حل چنین مشکلی است که به الگوی طراحی کارخانه انتزاعی نیاز است. نه، مشکلات خجالت سفر در زمان نیست، بلکه ایجاد گروه های مختلفی از اشیاء به هم پیوسته است. یک کارخانه انتزاعی یک رابط برای ایجاد تمام محصولات موجود (اشیاء خانوادگی) فراهم می کند. یک کارخانه انتزاعی معمولاً چندین پیاده سازی دارد. هر یک از آنها مسئول ایجاد محصولات یکی از تغییرات هستند. به عنوان بخشی از استراتژی، ما یک کارخانه انتزاعی خواهیم داشت که پیاده نظام انتزاعی، کمانداران و سواره نظام و همچنین اجرای این کارخانه را ایجاد می کند. کارخانه ای که لژیونرهای رومی ایجاد می کند و مثلاً کارخانه ای که جنگجویان کارتاژنی را ایجاد می کند. انتزاع مهمترین اصل این الگو است. مشتریان کارخانه با آن و با محصولات فقط از طریق رابط های انتزاعی کار می کنند. بنابراین، ما مجبور نیستیم به این فکر کنیم که در حال حاضر چه نوع رزمندگانی را ایجاد می کنیم، بلکه این مسئولیت را به اجرای خاصی از کارخانه انتزاعی منتقل می کنیم.

ما به اتوماسیون کافی شاپ ادامه می دهیم

در آخرین سخنرانی الگوی روش کارخانه را بررسی کردیم که با کمک آن توانستیم تجارت قهوه را گسترش دهیم و چندین نقطه جدید فروش قهوه را افتتاح کنیم. امروز ما به کار خود برای مدرن کردن تجارت خود ادامه خواهیم داد. با استفاده از الگوی کارخانه ای انتزاعی، پایه و اساس یک برنامه دسکتاپ جدید را برای سفارش آنلاین قهوه خواهیم گذاشت. وقتی برنامه ای را برای دسکتاپ می نویسیم، همیشه باید به فکر کراس پلتفرم باشیم. برنامه ما باید هم روی macOS و هم روی ویندوز کار کند (اسپویلر: لینوکس به عنوان تکلیف برای شما باقی خواهد ماند). برنامه ما چگونه خواهد بود؟ بسیار ساده: این فرمی است که از یک فیلد متنی، یک فیلد انتخابی و یک دکمه تشکیل شده است. اگر تجربه استفاده از سیستم عامل های مختلف را دارید، قطعا متوجه شده اید که در ویندوز دکمه ها متفاوت از مک رندر می شوند. مثل هر چیز دیگری... خب، بیایید شروع کنیم. همانطور که احتمالاً قبلاً متوجه شده اید، در نقش خانواده محصول، عناصر رابط گرافیکی خواهیم داشت:
  • دکمه ها؛
  • فیلدهای متنی؛
  • زمینه های انتخاب
سلب مسئولیت. در هر رابط می‌توانیم متدهایی مانند onClick، onValueChangedیا را تعریف کنیم onInputChanged. آن ها روش هایی که به ما امکان می دهند رویدادهای مختلف را مدیریت کنیم (کلیک کردن روی یک دکمه، وارد کردن متن، انتخاب یک مقدار در کادر انتخاب). همه اینها به عمد حذف شده است تا مثال اضافه نشود و برای مطالعه الگوی کارخانه بصری تر شود. بیایید رابط های انتزاعی را برای محصولات خود تعریف کنیم:
public interface Button {}
public interface Select {}
public interface TextField {}
برای هر سیستم عامل، باید عناصر رابط را به سبک آن سیستم عامل ایجاد کنیم. ما برای ویندوز و MacOS می نویسیم. بیایید پیاده سازی هایی برای ویندوز ایجاد کنیم:
public class WindowsButton implements Button {
}

public class WindowsSelect implements Select {
}

public class WindowsTextField implements TextField {
}
حالا برای MacOS هم همینطور:
public class MacButton implements Button {
}

public class MacSelect implements Select {
}

public class MacTextField implements TextField {
}
عالی. اکنون می‌توانیم کارخانه انتزاعی خود را راه‌اندازی کنیم، که تمام انواع محصولات انتزاعی موجود را ایجاد می‌کند:
public interface GUIFactory {

    Button createButton();
    TextField createTextField();
    Select createSelect();

}
کامل. همانطور که می بینید، تا کنون هیچ چیز پیچیده ای وجود ندارد. سپس همه چیز به همین سادگی است. بر اساس قیاس با محصولات، ما پیاده سازی های مختلفی از کارخانه خود را برای هر سیستم عامل ایجاد می کنیم. بیایید با ویندوز شروع کنیم:
public class WindowsGUIFactory implements GUIFactory {
    public WindowsGUIFactory() {
        System.out.println("Creating gui factory for Windows OS");
    }

    public Button createButton() {
        System.out.println("Creating Button for Windows OS");
        return new WindowsButton();
    }

    public TextField createTextField() {
        System.out.println("Creating TextField for Windows OS");
        return new WindowsTextField();
    }

    public Select createSelect() {
        System.out.println("Creating Select for Windows OS");
        return new WindowsSelect();
    }
}
خروجی کنسول در داخل متدها و سازنده ها اضافه شده است تا نحوه عملکرد آن را بیشتر نشان دهد. اکنون برای macOS:
public class MacGUIFactory implements GUIFactory {
    public MacGUIFactory() {
        System.out.println("Creating gui factory for macOS");
    }

    @Override
    public Button createButton() {
        System.out.println("Creating Button for macOS");
        return new MacButton();
    }

    @Override
    public TextField createTextField() {
        System.out.println("Creating TextField for macOS");
        return new MacTextField();
    }

    @Override
    public Select createSelect() {
        System.out.println("Creating Select for macOS");
        return new MacSelect();
    }
}
نکته: هر متد با توجه به امضای خود، یک نوع انتزاعی را برمی گرداند. اما در داخل روش ما یک پیاده سازی ملموس از محصول ایجاد می کنیم. این تنها جایی است که ما ایجاد نمونه های خاص را کنترل می کنیم. حالا نوبت نوشتن کلاس فرم است. این یک کلاس جاوا است که فیلدهای آن عناصر رابط هستند:
public class OrderCoffeeForm {
    private final TextField customerNameTextField;
    private final Select coffeTypeSelect;
    private final Button orderButton;

    public OrderCoffeeForm(GUIFactory factory) {
        System.out.println("Creating order coffee form");
        customerNameTextField = factory.createTextField();
        coffeTypeSelect = factory.createSelect();
        orderButton = factory.createButton();
    }
}
یک کارخانه انتزاعی به سازنده فرم منتقل می شود، که عناصر رابط را ایجاد می کند. پیاده سازی کارخانه مورد نیاز را به سازنده منتقل می کنیم تا بتوانیم عناصر رابط را برای یک سیستم عامل خاص ایجاد کنیم.
public class Application {
    private OrderCoffeeForm orderCoffeeForm;

    public void drawOrderCoffeeForm() {
        // Определим Name операционной системы, получив meaning системной проперти через System.getProperty
        String osName = System.getProperty("os.name").toLowerCase();
        GUIFactory guiFactory;

        if (osName.startsWith("win")) { // Для windows
            guiFactory = new WindowsGUIFactory();
        } else if (osName.startsWith("mac")) { // Для mac
            guiFactory = new MacGUIFactory();
        } else {
            System.out.println("Unknown OS, can't draw form :( ");
            return;
        }
        orderCoffeeForm = new OrderCoffeeForm(guiFactory);
    }

    public static void main(String[] args) {
        Application application = new Application();
        application.drawOrderCoffeeForm();
    }
}
اگر برنامه را روی ویندوز اجرا کنیم، خروجی زیر را دریافت می کنیم:

Creating gui factory for Windows OS
Creating order coffee form
Creating TextField for Windows OS
Creating Select for Windows OS
Creating Button for Windows OS
در مک خروجی به صورت زیر خواهد بود:

Creating gui factory for macOS
Creating order coffee form
Creating TextField for macOS
Creating Select for macOS
Creating Button for macOS
در لینوکس:

Unknown OS, can't draw form :( 
خوب، من و شما به این نتیجه می رسیم. ما یک چارچوب برای یک برنامه رابط کاربری گرافیکی نوشتیم که دقیقاً آن عناصر رابط را ایجاد می کند که برای یک سیستم عامل خاص مناسب است. بیایید به طور خلاصه آنچه را که ایجاد کردیم تکرار کنیم:
  • خانواده محصول: فیلد ورودی، فیلد انتخاب و دکمه.
  • پیاده سازی های مختلف این خانواده از محصولات، برای ویندوز و macOS.
  • یک کارخانه انتزاعی، که در آن رابطی را برای ایجاد محصولات خود تعریف کردیم.
  • دو پیاده سازی از کارخانه ما که هر کدام وظیفه ایجاد یک خانواده خاص از محصولات را بر عهده دارند.
  • یک فرم، یک کلاس جاوا که فیلدهای آن عناصر واسط انتزاعی هستند که در سازنده با مقادیر مورد نیاز با استفاده از یک کارخانه انتزاعی مقداردهی اولیه می شوند.
  • کلاس برنامه در داخل آن فرمی ایجاد می کنیم که با آن پیاده سازی مورد نیاز کارخانه خود را به سازنده منتقل می کنیم.
کل: ما الگوی کارخانه انتزاعی را پیاده سازی کرده ایم.

Abstract Factory: دستورالعمل استفاده

Abstract Factory یک الگوی طراحی برای مدیریت ایجاد خانواده های مختلف محصول بدون گره خوردن به کلاس های محصول خاص است. هنگام استفاده از این الگو باید:
  1. خود خانواده های محصول را تعریف کنید. بیایید فرض کنیم دو تا از آنها داریم:
    • SpecificProductA1،SpecificProductB1
    • SpecificProductA2،SpecificProductB2
  2. برای هر محصول در خانواده، یک کلاس انتزاعی (رابط) تعریف کنید. در مورد ما این است:
    • ProductA
    • ProductB
  3. در هر خانواده محصول، هر محصول باید رابط تعریف شده در مرحله 2 را پیاده سازی کند.
  4. یک کارخانه انتزاعی ایجاد کنید، با متدهای ایجاد برای هر محصول که در مرحله 2 تعریف شده است. در مورد ما، این روش ها عبارتند از:
    • ProductA createProductA();
    • ProductB createProductB();
  5. پیاده سازی های کارخانه انتزاعی را ایجاد کنید تا هر پیاده سازی ایجاد محصولات یک خانواده را کنترل کند. برای این کار در داخل هر پیاده سازی کارخانه انتزاعی باید تمامی روش های ایجاد را پیاده سازی کرد تا پیاده سازی های انضمامی محصولات در داخل آنها ایجاد و برگردانده شود.
در زیر یک نمودار UML وجود دارد که دستورالعمل‌های توضیح داده شده در بالا را نشان می‌دهد: الگوهای طراحی: AbstractFactory - 3حالا بیایید کد این دستورالعمل را بنویسیم:
// Определим общие интерфейсы продуктов
public interface ProductA {}
public interface ProductB {}

// Создадим различные реализации (семейства) наших продуктов
public class SpecificProductA1 implements ProductA {}
public class SpecificProductB1 implements ProductB {}

public class SpecificProductA2 implements ProductA {}
public class SpecificProductB2 implements ProductB {}

// Создадим абстрактную фабрику
public interface AbstractFactory {
    ProductA createProductA();
    ProductB createProductB();
}

// Создадим реализацию абстрактной фабрики для создания продуктов семейства 1
public class SpecificFactory1 implements AbstractFactory {

    @Override
    public ProductA createProductA() {
        return new SpecificProductA1();
    }

    @Override
    public ProductB createProductB() {
        return new SpecificProductB1();
    }
}

// Создадим реализацию абстрактной фабрики для создания продуктов семейства 1
public class SpecificFactory2 implements AbstractFactory {

    @Override
    public ProductA createProductA() {
        return new SpecificProductA2();
    }

    @Override
    public ProductB createProductB() {
        return new SpecificProductB2();
    }
}

مشق شب

برای تثبیت مواد می توانید 2 کار انجام دهید:
  1. برنامه سفارش قهوه را بهبود دهید تا در لینوکس کار کند.
  2. کارخانه انتزاعی خود را برای تولید واحدهای هر استراتژی ایجاد کنید. این می تواند یک استراتژی تاریخی با ارتش های واقعی باشد یا یک فانتزی با اورک ها، کوتوله ها و الف ها. نکته اصلی این است که برای شما جالب است. خلاق باشید، پین‌ها را به کنسول پست کنید و از یادگیری الگوها لذت ببرید!
نظرات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION