JavaRush /مدونة جافا /Random-AR /أنماط التصميم: طريقة المصنع

أنماط التصميم: طريقة المصنع

نشرت في المجموعة
مرحبًا! سنواصل اليوم دراسة أنماط التصميم والحديث عن طريقة المصنع. أنماط التصميم: طريقة المصنع - 1سوف تكتشف ما هو وما هي المهام التي يناسبها هذا القالب. سننظر إلى نمط التصميم هذا عمليًا ونستكشف بنيته. وحتى يتضح لك كل ما سبق، عليك أن تفهم المواضيع التالية:
  1. الميراث في جاوة.
  2. الأساليب والطبقات المجردة في جافا

ما هي المشكلة التي تحلها طريقة المصنع؟

في جميع أنماط تصميم المصانع، هناك مجموعتان من المشاركين - المبدعون (المصانع نفسها) والمنتجات (الأشياء التي أنشأتها المصانع). تخيل الموقف: لدينا مصنع ينتج سيارات تحت العلامة التجارية AutoRush. إنها تعرف كيفية إنشاء نماذج سيارات بأنواع مختلفة من الأجسام:
  • سيارات السيدان
  • محطة العربات
  • كوبيه
كانت الأمور تسير على ما يرام بالنسبة لنا لدرجة أننا في أحد الأيام استوعبنا مخاوف OneAuto. كمديرين عاقلين، لا نريد أن نفقد عملاء OneAuto، ومهمتنا هي إعادة هيكلة الإنتاج بطريقة تمكننا من إنتاج:
  • سيارات السيدان AutoRush
  • عربات محطة AutoRush
  • كوبيه أوتوراش
  • سيارات السيدان 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;
    }

}
الآن يمكننا تمرير تنفيذ المصنع المطلوب إلى CoffeeShop. دعونا نرى كيف سيبدو رمز طلب القهوة من المقاهي المختلفة. على سبيل المثال، كابتشينو في الأساليب الإيطالية والأمريكية:
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);
    }
}
تهانينا. لقد قمنا للتو بتنفيذ نمط تصميم طريقة المصنع في المقهى الخاص بنا.

طريقة عمل طريقة المصنع

الآن دعونا نلقي نظرة فاحصة على ما حصلنا عليه. ويوضح الرسم البياني أدناه الفئات الناتجة. الكتل الخضراء هي فئات منشئي المحتوى، والكتل الزرقاء هي فئات المنتجات. أنماط التصميم: طريقة المصنع - 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