CodeGym /وبلاگ جاوا /Random-FA /الگوهای طراحی: روش کارخانه
John Squirrels
مرحله
San Francisco

الگوهای طراحی: روش کارخانه

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

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

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

کمی در مورد الگوی کارخانه

یادآوری می کنم که قبلا یک کافی شاپ مجازی کوچک ساخته بودیم. با کمک یک کارخانه ساده، نحوه ایجاد انواع قهوه را یاد گرفتیم. امروز این مثال را دوباره کار خواهیم کرد. بیایید به یاد بیاوریم که کافی شاپ ما با کارخانه ساده اش چگونه به نظر می رسید. کلاس قهوه داشتیم:
public class Coffee {
    public void grindCoffee(){
        // Grind the coffee
    }
    public void makeCoffee(){
        // Brew the coffee
    }
    public void pourIntoCup(){
        // Pour into a cup
    }
}
و چندین کلاس کودک مربوط به انواع خاصی از قهوه که کارخانه ما می تواند تولید کند:
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("Here's your coffee! Thanks! Come again!");
        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("Here's your coffee! Thanks! Come again!");
    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) {
        /*
            Order an Italian-style cappuccino:
            1. Create a factory for making Italian coffee
            2. Create a new coffee shop, passing the Italian coffee factory to it through the constructor
            3. Order our coffee
         */
        SimpleItalianCoffeeFactory italianCoffeeFactory = new SimpleItalianCoffeeFactory();
        CoffeeShop italianCoffeeShop = new CoffeeShop(italianCoffeeFactory);
        italianCoffeeShop.orderCoffee(CoffeeType.CAPPUCCINO);


         /*
            Order an American-style cappuccino
            1. Create a factory for making American coffee
            2. Create a new coffee shop, passing the American coffee factory to it through the constructor
            3. Order our coffee
         */
        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(){
        // Brew the coffee
    }
    public void pourIntoCup(){
        // Pour into a cup
    }
}
مرحله 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("Here's your coffee! Thanks! Come again!");
        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);
    }
}
تبریک می گویم. ما فقط الگوی طراحی روش کارخانه را با استفاده از کافی شاپ خود به عنوان مثال اجرا کردیم.

اصل روش های کارخانه ای

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

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

الگوهای طراحی: روش کارخانه - 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