نمط Builder
جزء من قسم البرمجة كائنية التوجه في رحلة Java على Coddy. الدرس 67 من 87.
نمط Builder هو نمط تصميم إنشائي يحل مشكلة شائعة: إنشاء كائنات معقدة تحتوي على العديد من المعلمات الاختيارية. بدلًا من إنشاء عدة مُنشئات أو تمرير null للمعلمات غير المستخدمة، يتيح لك Builder إنشاء الكائنات خطوةً بخطوة.
لنفترض إنشاء كائن User مع fields مطلوبة (name، email) وأخرى اختيارية (age، phone، address). من دون Builder، ستحتاج إلى مُنشئات متداخلة أو مُنشئ فوضوي ذي العديد من parameter. يقدّم نمط Builder أسلوبًا أكثر نظافة:
public class User {
private final String name; // مطلوب
private final String email; // مطلوب
private final int age; // اختياري
private final String phone; // اختياري
private User(UserBuilder builder) {
this.name = builder.name;
this.email = builder.email;
this.age = builder.age;
this.phone = builder.phone;
}
public static class UserBuilder {
private final String name;
private final String email;
private int age;
private String phone;
public UserBuilder(String name, String email) {
this.name = name;
this.email = email;
}
public UserBuilder age(int age) {
this.age = age;
return this;
}
public UserBuilder phone(String phone) {
this.phone = phone;
return this;
}
public User build() {
return new User(this);
}
}
}تُرجع methods الخاصة بـ Builder القيمة this، مما يتيح method التسلسل: طريقة سلسة وسهلة القراءة لإنشاء الكائنات:
User user = new User.UserBuilder("Alice", "alice@email.com")
.age(25)
.phone("555-1234")
.build();لاحظ أن مُنشئ User خاص: لا يمكن إنشاء الكائنات إلا من خلال Builder. يتألق هذا النمط عندما تحتوي الكائنات على العديد من الحقول الاختيارية، مما يجعل شيفرتك أكثر قابلية للقراءة وأقل عرضة للأخطاء مقارنةً بقوائم المعلمات الطويلة.
التحدي
سهللنَبْنِ نظامًا لطلب البيتزا باستخدام نمط Builder! بدلًا من التعامل مع constructor يأخذ عشرات parameter لجميع الإضافات والخيارات الممكنة، ستنشئ أداة إنشاء سلسة تجعل تخصيص البيتزا واضحًا وسهل القراءة.
ستنظّم التعليمات البرمجية عبر ملفين:
Pizza.java: أنشئPizzaclassيستخدم نمط Builder في الإنشاء. يجب أن تحتوي البيتزا علىfieldsالتالية:size(String) - مطلوب، ويمثل حجم البيتزاcheese(boolean) - اختياري، وقيمته الافتراضية هي falsepepperoni(boolean) - اختياري، وقيمته الافتراضية هي falsemushrooms(boolean) - اختياري، وقيمته الافتراضية هي falseيجب أن يكون
Pizzaconstructorخاصًا وأن يقبلPizzaBuilderفقط باعتبارهparameter، مع نسخ جميع القيم من أداة الإنشاء إلىfieldsالخاصة بالبيتزا.ضمّن
getDescription()methodيعيد سلسلة نصية بهذا التنسيق:[size] Pizza with: [toppings]حيث تكونtoppingsقائمة مفصولة بفواصل للإضافات التي قيمتها true (Cheese, Pepperoni, Mushrooms). إذا لم يتم اختيار أي إضافات، فيجب أن يكون جزء الإضافات ببساطةno toppings.أنشئ
classداخلية ثابتة باسمPizzaBuilderتتضمن:-
constructorيأخذsizeparameterالمطلوب -
methodsباسمcheese()وpepperoni()وmushrooms()، يعيّن كل منها القيمة المنطقية الخاصة بها إلى true ويعيدthisللسماح بالتسلسل -
build()methodيعيدPizzaجديدة
-
Main.java: أظهر أداة إنشاء البيتزا أثناء عملها! ستتلقى أربعة مدخلات: حجم البيتزا (String)، وثلاث قيم yes/no (Strings) تشير إلى ما إذا كان ينبغي إضافة cheese وpepperoni وmushrooms على التوالي.أنشئ
PizzaBuilderباستخدام الحجم المُعطى. ثم، استنادًا إلى كل مدخلة yes/no، قم بتسلسلmethodsالخاصة بالإضافة المناسبة. إذا كانت المدخلة هي"yes"، فاستدعِmethodالخاصة بتلك الإضافة؛ وإذا كانت"no"، فتجاوزها. أخيرًا، استدعِbuild()لإنشاء البيتزا.اطبع نتيجة استدعاء
getDescription()على البيتزا المكتملة.
ستتلقى أربع مدخلات بالترتيب: size (String)، وadd cheese (String: "yes" أو "no")، وadd pepperoni (String: "yes" أو "no")، وadd mushrooms (String: "yes" أو "no").
على سبيل المثال، عند استخدام المدخلات Large وyes وno وyes، سيكون الناتج: Large Pizza with: Cheese, Mushrooms
لاحظ كيف يتيح لك نمط Builder إنشاء بيتزا بأي مجموعة من الإضافات دون الحاجة إلى constructors منفصلة لكل احتمال!
جرّب بنفسك
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// قراءة المدخلات
String size = scanner.nextLine();
String addCheese = scanner.nextLine();
String addPepperoni = scanner.nextLine();
String addMushrooms = scanner.nextLine();
// TODO: إنشاء PizzaBuilder بالحجم المحدد
// TODO: ربط دوال الإضافات بناءً على مدخلات yes/no
// TODO: بناء البيتزا وطباعة وصفها
}
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس البرمجة كائنية التوجه
1أساسيات الـ OOP
الملفات الخارجيةمقدمة في الـ OOPالفئات (Classes) مقابل الكائنات (Objects)الكلمة المفتاحية thisالدوال (Methods)الحقول (Attributes)دالة البناء (Constructor)تعدد أشكال دالة البناء (Constructor Overloading)مراجعة - آلة حاسبة بسيطة4الوراثة
الوراثة الأساسية (extends)الكلمة المفتاحية superإعادة تعريف الدوال (@Override)تسلسل المنشئات (Constructor Chaining)كلاس Objectالوراثة الأحادية ومتعددة المستوياتلماذا لا توجد وراثة متعددة للكلاساتمراجعة - هيكلية الموظفين7الدوال الخاصة وفئة Object
دالة toString()equals() و hashCode()دالة clone()compareTo() و Comparableواجهة Comparatorمراجعة - الترتيب المخصص2محددات الوصول والتغليف
نظرة عامة على مستويات الوصولدوال Getter و Setterإخفاء البياناتالكلمة المفتاحية finalمراجعة - مدير الحساب البنكي5تعدد الأشكال (Polymorphism)
أساسيات الـ Method Overloadingالـ Method Overriding (في وقت التشغيل)الـ Upcasting والـ Downcastingمعامل الـ instanceofالفئات والدوال المجردة (Abstract)مراجعة - حاسبة الأشكال8مفاهيم OOP المتقدمة
الـ Composition مقابل الـ Inheritanceالـ Aggregation مقابل الـ Compositionالفئات الداخلية والمتداخلة والمجهولة (Inner, Nested & Anonymous)الـ Enums ودوالهاالـ Records (Java 16+)الـ Sealed Classes (Java 17+)11أنماط التصميم - الجزء الأول
مقدمة في أنماط التصميمنمط Singletonنمط Factoryنمط Builderنمط Observerنمط Strategy3خصائص الفئة والعضو الساكن
المتغيرات الخاصة بالكائن مقابل المتغيرات الساكنةالدوال الساكنةالكتل البرمجية الساكنةالثوابت (static final)ملخص - العداد والأدوات المساعدة6الواجهات (Interfaces) والأصناف المجردة (Abstract Classes)
مقدمة في الواجهات (Interfaces)تنفيذ الواجهات (Interfaces)تنفيذ واجهات متعددةالـ Default و Static في الواجهاتالأصناف المجردة مقابل الواجهاتالواجهات الوظيفية (Functional Interfaces)مراجعة - نظام الدفع9الأنواع العامة (Generics)
مقدمة في الأنواع العامةالأصناف العامة (Generic Classes)الدوال العامة (Generic Methods)معاملات الأنواع المقيدةالرموز البديلة (?, extends, super)مراجعة - الحاويات العامة12أنماط التصميم - الجزء الثاني
نمط الأمرنمط المحولنمط المزيننمط طريقة القالبنمط الحالةنمط التركيبنمط المكررتدرّب بنفسك: مترجم Java عبر الإنترنت