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

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

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

روش کارخانه چه مشکلی را حل می کند؟

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

کمی در مورد قالب کارخانه

یادآوری کنم: ما با شما یک کافی شاپ مجازی کوچک ساختیم. در آن یاد گرفتیم که چگونه با استفاده از یک کارخانه ساده انواع مختلف قهوه را بسازیم. امروز این مثال را اصلاح خواهیم کرد. بیایید به یاد بیاوریم که کافی شاپ ما با یک کارخانه ساده چه شکلی بود. کلاس قهوه داشتیم:
public class Coffee {
    public void grindCoffee(){
        // перемалываем кофе
    }
    public void makeCoffee(){
        // делаем кофе
    }
    public void pourIntoCup(){
        // наливаем в чашку
    }
}
و همچنین چندین نفر از وارثان او - انواع خاصی از قهوه که کارخانه ما می تواند تولید کند:
public class Americano extends Coffee {}
public class Cappuccino extends Coffee {}
public class CaffeLatte extends Coffee {}
public class Espresso extends Coffee {}
برای سهولت در پذیرش سفارش، نقل و انتقالات را معرفی کرده ایم:
public enum CoffeeType {
    ESPRESSO,
    AMERICANO,
    CAFFE_LATTE,
    CAPPUCCINO
}
خود کارخانه قهوه به این شکل بود:
public class SimpleCoffeeFactory {
    public Coffee createCoffee (CoffeeType type) {
        Coffee coffee = null;

        switch (type) {
            case AMERICANO:
                coffee = new Americano();
                break;
            case ESPRESSO:
                coffee = new Espresso();
                break;
            case CAPPUCCINO:
                coffee = new Cappuccino();
                break;
            case CAFFE_LATTE:
                coffee = new CaffeLatte();
                break;
        }

        return coffee;
    }
}
و در نهایت، خود کافی شاپ:
public class CoffeeShop {

    private final SimpleCoffeeFactory coffeeFactory;

    public CoffeeShop(SimpleCoffeeFactory coffeeFactory) {
        this.coffeeFactory = coffeeFactory;
    }

    public Coffee orderCoffee(CoffeeType type) {
        Coffee coffee = coffeeFactory.createCoffee(type);
        coffee.grindCoffee();
        coffee.makeCoffee();
        coffee.pourIntoCup();

        System.out.println("Вот ваш кофе! Спасибо, приходите еще!");
        return coffee;
    }
}

نوسازی یک کارخانه ساده

کافی شاپ ما خوب است. آنقدر که به فکر گسترش هستیم. ما می خواهیم چندین نقطه جدید را باز کنیم. ما به عنوان افراد مبتکر، کافی شاپ های یکنواخت را راه اندازی نمی کنیم. من می خواهم هر کدام پیچش خاص خود را داشته باشد. بنابراین، برای شروع، ما دو نکته را باز می کنیم: در سبک های ایتالیایی و آمریکایی. تغییرات نه تنها بر فضای داخلی، بلکه بر نوشیدنی ها نیز تأثیر می گذارد:
  • در یک کافی شاپ ایتالیایی ما منحصراً از مارک های قهوه ایتالیایی با آسیاب و برشته کردن ویژه استفاده خواهیم کرد.
  • قسمت آمریکایی کمی بزرگتر خواهد بود و با هر سفارش مارشمالو آب شده - مارشمالو سرو می کنیم.
تنها چیزی که بدون تغییر باقی می ماند مدل کسب و کار ما است که خود را به خوبی ثابت کرده است. اگر به زبان کد صحبت کنیم، این اتفاق می افتد. ما 4 کلاس محصول داشتیم:
public class Americano extends Coffee {}
public class Cappuccino extends Coffee {}
public class CaffeLatte extends Coffee {}
public class Espresso extends Coffee {}
و می شود 8:
public class ItalianStyleAmericano extends Coffee {}
public class ItalianStyleCappucino extends Coffee {}
public class ItalianStyleCaffeLatte extends Coffee {}
public class ItalianStyleEspresso extends Coffee {}

public class AmericanStyleAmericano extends Coffee {}
public class AmericanStyleCappucino extends Coffee {}
public class AmericanStyleCaffeLatte extends Coffee {}
public class AmericanStyleEspresso extends Coffee {}
از آنجایی که می‌خواهیم مدل کسب‌وکار فعلی را بدون تغییر نگه داریم، می‌خواهیم این روش orderCoffee(CoffeeType type)دستخوش حداقل تغییرات شود. بیایید نگاهی به آن بیندازیم:
public Coffee orderCoffee(CoffeeType type) {
    Coffee coffee = coffeeFactory.createCoffee(type);
    coffee.grindCoffee();
    coffee.makeCoffee();
    coffee.pourIntoCup();

    System.out.println("Вот ваш кофе! Спасибо, приходите еще!");
    return coffee;
}
چه گزینه هایی داریم؟ ما قبلاً می دانیم چگونه یک کارخانه بنویسیم، درست است؟ ساده ترین چیزی که بلافاصله به ذهن می رسد این است که دو کارخانه مشابه را بنویسیم و سپس اجرای مورد نیاز را به کافی شاپ خود در سازنده منتقل کنیم. اونوقت کلاس کافی شاپ عوض نمیشه. ابتدا باید یک کلاس کارخانه جدید ایجاد کنیم، از کارخانه ساده خود ارث ببریم و createCoffee (CoffeeType type). بیایید کارخانه هایی برای ایجاد قهوه به سبک های ایتالیایی و آمریکایی بنویسیم:
public class SimpleItalianCoffeeFactory extends SimpleCoffeeFactory {

    @Override
    public Coffee createCoffee (CoffeeType type) {
        Coffee coffee = null;
        switch (type) {
            case AMERICANO:
                coffee = new ItalianStyleAmericano();
                break;
            case ESPRESSO:
                coffee = new ItalianStyleEspresso();
                break;
            case CAPPUCCINO:
                coffee = new ItalianStyleCappuccino();
                break;
            case CAFFE_LATTE:
                coffee = new ItalianStyleCaffeLatte();
                break;
        }
        return coffee;
    }
}

public class SimpleAmericanCoffeeFactory extends SimpleCoffeeFactory{

    @Override
    public Coffee createCoffee (CoffeeType type) {
        Coffee coffee = null;

        switch (type) {
            case AMERICANO:
                coffee = new AmericanStyleAmericano();
                break;
            case ESPRESSO:
                coffee = new AmericanStyleEspresso();
                break;
            case CAPPUCCINO:
                coffee = new AmericanStyleCappuccino();
                break;
            case CAFFE_LATTE:
                coffee = new AmericanStyleCaffeLatte();
                break;
        }

        return coffee;
    }

}
اکنون می توانیم اجرای کارخانه ای مورد نیاز را به کافی شاپ منتقل کنیم. بیایید ببینیم کد سفارش قهوه از کافی شاپ های مختلف چگونه خواهد بود. به عنوان مثال، کاپوچینو در سبک های ایتالیایی و آمریکایی:
public class Main {
    public static void main(String[] args) {
        /*
            Закажем капучино в итальянском стиле:
            1. Создадим фабрику для приготовления итальянского кофе
            2. Создадим новую кофейню, передав ей в конструкторе фабрику итальянского кофе
            3. Закажем наш кофе
         */
        SimpleItalianCoffeeFactory italianCoffeeFactory = new SimpleItalianCoffeeFactory();
        CoffeeShop italianCoffeeShop = new CoffeeShop(italianCoffeeFactory);
        italianCoffeeShop.orderCoffee(CoffeeType.CAPPUCCINO);


         /*
            Закажем капучино в американском стиле
            1. Создадим фабрику для приготовления американского кофе
            2. Создадим новую кофейню, передав ей в конструкторе фабрику американского кофе
            3. Закажем наш кофе
         */
        SimpleAmericanCoffeeFactory americanCoffeeFactory = new SimpleAmericanCoffeeFactory();
        CoffeeShop americanCoffeeShop = new CoffeeShop(americanCoffeeFactory);
        americanCoffeeShop.orderCoffee(CoffeeType.CAPPUCCINO);
    }
}
ما دو کافی شاپ مختلف ایجاد کردیم و هر کدام را به کارخانه مورد نیاز انتقال دادیم. از یک طرف به هدف خود رسیده ایم، اما از طرف دیگر ... چیزی روح غیرقابل مهار کارآفرین را می خراشد ... بیایید بفهمیم چه مشکلی دارد. اولا، فراوانی کارخانه ها. آیا می توان هر بار برای یک نقطه جدید، کارخانه خود را ایجاد کرد و علاوه بر آن، اطمینان حاصل کرد که هنگام ایجاد کافی شاپ، کارخانه مورد نیاز به سازنده منتقل می شود؟ دوم اینکه هنوز یک کارخانه ساده است. فقط کمی مدرن شده است. ما هنوز در حال مطالعه یک الگوی جدید در اینجا هستیم. ثالثاً، آیا نمی توان آن را به گونه ای دیگر انجام داد؟ خیلی خوب خواهد بود اگر بتوانیم تمام سوالات مربوط به تهیه قهوه را در داخل کلاس بومی سازی کنیم CoffeeShop، فرآیندهای تولید قهوه و سرویس دهی را به هم مرتبط کنیم، اما در عین حال انعطاف کافی برای تهیه قهوه در سبک های مختلف را حفظ کنیم. پاسخ این است که بله، شما می توانید. به این الگوی طراحی روش کارخانه می گویند.

از یک کارخانه ساده تا یک روش کارخانه ای

برای حل مشکل تا حد امکان کارآمد، ما:
  1. بیایید متد را createCoffee(CoffeeType type)به کلاس برگردانیم CoffeeShop.
  2. بیایید این روش را انتزاعی کنیم.
  3. خود کلاس CoffeeShopانتزاعی می شود.
  4. کلاس CoffeeShopوارثانی خواهد داشت.
بله دوست یک کافی شاپ ایتالیایی چیزی نیست جز وارث این کلاس CoffeeShopکه روشی createCoffee(CoffeeType type)مطابق با بهترین سنت های باریستاهای ایتالیایی را اجرا می کند. بنابراین، به ترتیب. مرحله 1. بیایید کلاس را Coffeeانتزاعی کنیم. ما در حال حاضر دو خانواده از محصولات مختلف داریم. نوشیدنی های قهوه ایتالیایی و آمریکایی هنوز یک نیای مشترک دارند: Coffee. درست است که آن را انتزاعی کنیم:
public abstract class Coffee {
    public void makeCoffee(){
        // делаем кофе
    }
    public void pourIntoCup(){
        // наливаем в чашку
    }
}
مرحله 2. CoffeeShopبا روشی انتزاعی آن را انتزاعی کنیدcreateCoffee(CoffeeType type)
public abstract class CoffeeShop {

    public Coffee orderCoffee(CoffeeType type) {
        Coffee coffee = createCoffee(type);

        coffee.makeCoffee();
        coffee.pourIntoCup();

        System.out.println("Вот ваш кофе! Спасибо, приходите еще!");
        return coffee;
    }

    protected abstract Coffee createCoffee(CoffeeType type);
}
مرحله 3. یک کافی شاپ ایتالیایی، یک طبقه از نسل کافی شاپ انتزاعی ایجاد کنید. در آن ما روش را createCoffee(CoffeeType type)با در نظر گرفتن ویژگی های ایتالیایی پیاده سازی می کنیم.
public class ItalianCoffeeShop extends CoffeeShop {

    @Override
    public Coffee createCoffee (CoffeeType type) {
        Coffee coffee = null;
        switch (type) {
            case AMERICANO:
                coffee = new ItalianStyleAmericano();
                break;
            case ESPRESSO:
                coffee = new ItalianStyleEspresso();
                break;
            case CAPPUCCINO:
                coffee = new ItalianStyleCappuccino();
                break;
            case CAFFE_LATTE:
                coffee = new ItalianStyleCaffeLatte();
                break;
        }
        return coffee;
    }
}
مرحله 4. بیایید همین کار را برای یک کافی شاپ به سبک آمریکایی انجام دهیم.
public class AmericanCoffeeShop extends CoffeeShop {
    @Override
    public Coffee createCoffee (CoffeeType type) {
        Coffee coffee = null;

        switch (type) {
            case AMERICANO:
                coffee = new AmericanStyleAmericano();
                break;
            case ESPRESSO:
                coffee = new AmericanStyleEspresso();
                break;
            case CAPPUCCINO:
                coffee = new AmericanStyleCappuccino();
                break;
            case CAFFE_LATTE:
                coffee = new AmericanStyleCaffeLatte();
                break;
        }

        return coffee;
    }
}
مرحله 5. بیایید نگاهی به نحوه سفارش یک لاته آمریکایی و ایتالیایی بیندازیم:
public class Main {
    public static void main(String[] args) {
        CoffeeShop italianCoffeeShop = new ItalianCoffeeShop();
        italianCoffeeShop.orderCoffee(CoffeeType.CAFFE_LATTE);

        CoffeeShop americanCoffeeShop = new AmericanCoffeeShop();
        americanCoffeeShop.orderCoffee(CoffeeType.CAFFE_LATTE);
    }
}
تبریک می گویم. ما به تازگی الگوی طراحی روش کارخانه را در کافی شاپ خود اجرا کردیم.

روش کارخانه چگونه کار می کند

حالا بیایید نگاهی دقیق تر به آنچه به دست آوردیم بیندازیم. نمودار زیر کلاس های حاصل را نشان می دهد. بلوک های سبز کلاس های سازنده هستند، بلوک های آبی کلاس های محصول هستند. الگوهای طراحی: FactoryMethod - 2چه نتایجی می توان گرفت؟
  1. همه محصولات پیاده سازی از کلاس انتزاعی هستند Coffee.
  2. همه سازندگان پیاده سازی های کلاس انتزاعی هستند CoffeeShop.
  3. ما دو سلسله مراتب کلاسی موازی را مشاهده می کنیم:
    • سلسله مراتب محصولات ما نوادگان ایتالیایی و نوادگان آمریکایی را می بینیم
    • سلسله مراتب پدیدآورندگان. ما نوادگان ایتالیایی و نوادگان آمریکایی را می بینیم
  4. سوپرکلاس CoffeeShopهیچ اطلاعاتی در مورد اینکه کدام محصول خاص ( Coffee) ایجاد خواهد شد ندارد.
  5. یک سوپرکلاس CoffeeShopایجاد یک محصول خاص را به فرزندان خود محول می کند.
  6. هر کلاس decendant CoffeeShopیک متد کارخانه ای را createCoffee()مطابق با مشخصات خود پیاده سازی می کند. به عبارت دیگر در پیاده سازی های کلاس های سازندگان، تصمیم به تهیه یک محصول خاص بر اساس ویژگی های کلاس سازندگان گرفته می شود.
اکنون آماده تعریف الگوی روش کارخانه هستید . الگوی متد کارخانه، اینترفیس را برای ایجاد یک شی تعریف می‌کند، اما به کلاس‌های فرعی اجازه می‌دهد تا کلاس نمونه موردنظر را انتخاب کنند. بنابراین، روش Factory عملیات نمونه سازی را به زیر کلاس ها واگذار می کند. به طور کلی، به خاطر سپردن تعریف به اندازه درک چگونگی کارکرد چیزها مهم نیست.

ساختار روش کارخانه

الگوهای طراحی: FactoryMethod - 3نمودار بالا ساختار کلی الگوی روش کارخانه را نشان می دهد. چه چیز دیگری در اینجا مهم است؟
  1. کلاس Creator شامل پیاده سازی تمام متدهایی است که با محصولات تعامل دارند، به جز روش کارخانه.
  2. یک متد انتزاعی factoryMethod()باید توسط همه نوادگان کلاس پیاده سازی شود Creator.
  3. کلاس ConcreteCreatorروشی را پیاده سازی می کند factoryMethod()که مستقیماً یک محصول را تولید می کند.
  4. این کلاس وظیفه ایجاد محصولات خاص را بر عهده دارد. این تنها کلاس با اطلاعات در مورد ایجاد این محصولات است.
  5. همه محصولات باید یک رابط مشترک را پیاده سازی کنند - فرزندان یک کلاس محصول مشترک باشند. این امر ضروری است تا طبقاتی که از محصولات استفاده می کنند بتوانند در سطح انتزاعات به جای اجرای عینی بر روی آنها عمل کنند.

مشق شب

بنابراین، امروز ما کارهای زیادی انجام دادیم و الگوی طراحی روش کارخانه را مطالعه کردیم. وقت آن است که مطالبی را که پوشش داده اید یکپارچه کنید! وظیفه 1. روی باز کردن یک کافی شاپ دیگر کار کنید. می توان آن را به سبک انگلیسی یا اسپانیایی ساخت. یا حتی به سبک سفینه فضایی. بیایید رنگ خوراکی را به قهوه اضافه کنیم تا درخشنده شود و در کل قهوه فقط فضا خواهد بود! وظیفه 2. در آخرین سخنرانی، شما وظیفه ایجاد یک سوشی بار مجازی یا یک پیتزا فروشی مجازی را داشتید. وظیفه شما ایستادن نیست. امروز یاد گرفتید که چگونه می توانید از الگوی روش کارخانه برای رسیدن به موفقیت استفاده کنید. وقت آن است که از این دانش استفاده کنید و کسب و کار خود را گسترش دهید ;)
نظرات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION