مرحبًا! سنواصل اليوم دراسة أنماط التصميم والحديث عن طريقة المصنع. سوف تكتشف ما هو وما هي المهام التي يناسبها هذا القالب. سننظر إلى نمط التصميم هذا عمليًا ونستكشف بنيته. وحتى يتضح لك كل ما سبق، عليك أن تفهم المواضيع التالية:
- الميراث في جاوة.
- الأساليب والطبقات المجردة في جافا
ما هي المشكلة التي تحلها طريقة المصنع؟
في جميع أنماط تصميم المصانع، هناك مجموعتان من المشاركين - المبدعون (المصانع نفسها) والمنتجات (الأشياء التي أنشأتها المصانع). تخيل الموقف: لدينا مصنع ينتج سيارات تحت العلامة التجارية AutoRush. إنها تعرف كيفية إنشاء نماذج سيارات بأنواع مختلفة من الأجسام:- سيارات السيدان
- محطة العربات
- كوبيه
- سيارات السيدان 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;
}
}
تحديث مصنع بسيط
المقهى الخاص بنا يعمل بشكل جيد. لدرجة أننا نفكر في التوسع. نريد فتح عدة نقاط جديدة. باعتبارنا رجالًا مغامرين، فإننا لن ننتج مقاهي رتيبة. أريد أن يكون لكل واحد تطوره الخاص. لذلك، في البداية، سنفتح نقطتين: في الأساليب الإيطالية والأمريكية. لن تؤثر التغييرات على التصميم الداخلي فحسب، بل ستؤثر أيضًا على المشروبات:- في المقهى الإيطالي، سنستخدم ماركات القهوة الإيطالية حصريًا، مع طحن وتحميص خاص.
- سيكون الجزء الأمريكي أكبر قليلاً، ومع كل طلب سنقدم أعشاب من الفصيلة الخبازية المذابة - أعشاب من الفصيلة الخبازية.
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
، وربط عمليات صنع القهوة وخدمة الطلب، ولكن في نفس الوقت الحفاظ على مرونة كافية لصنع القهوة بأساليب مختلفة. الجواب هو نعم يمكنك. وهذا ما يسمى نمط تصميم طريقة المصنع.
من مصنع بسيط إلى طريقة المصنع
لحل المشكلة بأكبر قدر ممكن من الكفاءة، نقوم بما يلي:- دعنا نعيد الطريقة
createCoffee(CoffeeType type)
إلى الفصلCoffeeShop
. - دعونا نجعل هذه الطريقة مجردة.
CoffeeShop
سوف يصبح الفصل نفسه مجردًا.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);
}
}
تهانينا. لقد قمنا للتو بتنفيذ نمط تصميم طريقة المصنع في المقهى الخاص بنا.
طريقة عمل طريقة المصنع
الآن دعونا نلقي نظرة فاحصة على ما حصلنا عليه. ويوضح الرسم البياني أدناه الفئات الناتجة. الكتل الخضراء هي فئات منشئي المحتوى، والكتل الزرقاء هي فئات المنتجات. ما هي الاستنتاجات التي يمكن استخلاصها؟- جميع المنتجات هي تطبيقات للفئة المجردة
Coffee
. - جميع المبدعين هم تطبيقات للفئة المجردة
CoffeeShop
. - نلاحظ تسلسلين هرميين متوازيين:
- التسلسل الهرمي للمنتجات. نرى أحفادًا إيطاليين وأحفادًا أمريكيين
- التسلسل الهرمي للمبدعين. نرى أحفادًا إيطاليين وأحفادًا أمريكيين
- لا تحتوي الفئة الفائقة
CoffeeShop
على معلومات حول تطبيق المنتج المحدد (Coffee
) الذي سيتم إنشاؤه. - تقوم الطبقة المتفوقة
CoffeeShop
بتفويض إنشاء منتج معين إلى أحفادها. - تنفذ كل فئة تابعة
CoffeeShop
طريقة المصنعcreateCoffee()
وفقًا لتفاصيلها. بمعنى آخر، ضمن تطبيقات فئات المنشئ، يتم اتخاذ قرار لإعداد منتج معين بناءً على تفاصيل فئة المنشئ.
هيكل طريقة المصنع
يوضح الرسم البياني أعلاه الهيكل العام لنمط طريقة المصنع. ما هو المهم هنا؟- تحتوي فئة Creator على تطبيقات جميع الطرق التي تتفاعل مع المنتجات، باستثناء طريقة المصنع.
- يجب تنفيذ الطريقة المجردة
factoryMethod()
من قبل جميع أحفاد الفصلCreator
. - يطبق الفصل
ConcreteCreator
طريقةfactoryMethod()
تنتج المنتج مباشرة. - هذه الفئة مسؤولة عن إنشاء منتجات محددة. هذا هو الفصل الدراسي الوحيد الذي لديه معلومات حول إنشاء هذه المنتجات.
- يجب أن تطبق جميع المنتجات واجهة مشتركة - وأن تكون متحدرة من فئة منتجات مشتركة. يعد ذلك ضروريًا حتى تتمكن الفئات التي تستخدم المنتجات من العمل عليها على مستوى التجريد بدلاً من التنفيذ الملموس.
GO TO FULL VERSION