Menu
Coddy logo textTech
flag Ar iconالعربيةdown icon

نمط Builder

جزء من قسم Object Oriented Programming في رحلة Java على Coddy — الدرس 67 من 87.

يُعد نمط الباني (Builder Pattern) نمط تصميم إنشائي يحل مشكلة شائعة: وهي بناء كائنات معقدة تحتوي على العديد من المعاملات الاختيارية. فبدلاً من إنشاء عدة منشئات (constructors) أو تمرير null للمعاملات غير المستخدمة، يتيح لك نمط الباني بناء الكائنات خطوة بخطوة.

فكر في إنشاء كائن User بحقول مطلوبة (name, email) وأخرى اختيارية (age, phone, address). بدون نمط Builder، ستحتاج إلى منشئات متداخلة (telescoping constructors) أو منشئ فوضوي يحتوي على العديد من المعاملات (parameters). يوفر نمط 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);
        }
    }
}

تُرجع دوال الـ Builder القيمة this، مما يسمح بـ تسلسل الدوال (method chaining)—وهي طريقة سلسة وقابلة للقراءة لإنشاء الكائنات:

User user = new User.UserBuilder("Alice", "alice@email.com")
    .age(25)
    .phone("555-1234")
    .build();

لاحظ كيف أن المُنشئ User خاص (private)—لا يمكن إنشاء الكائنات إلا من خلال الـ Builder. يتألق هذا النمط عندما تحتوي الكائنات على العديد من الحقول الاختيارية، مما يجعل الكود الخاص بك أكثر قابلية للقراءة وأقل عرضة للأخطاء من قوائم المعاملات الطويلة.

challenge icon

التحدي

سهل

لنقم ببناء نظام لطلب البيتزا باستخدام نمط البناء (Builder Pattern)! بدلاً من التعامل مع منشئ (constructor) يأخذ عشرات المعاملات لجميع الإضافات والخيارات الممكنة، ستقوم بإنشاء باني سلس (fluent builder) يجعل تخصيص البيتزا نظيفاً وسهل القراءة.

ستقوم بتنظيم الكود الخاص بك عبر ملفين:

  • Pizza.java: قم بإنشاء فئة Pizza تستخدم نمط Builder للإنشاء. يجب أن تحتوي البيتزا الخاصة بك على الحقول التالية:

    size (String) - مطلوب، يمثل حجم البيتزا

    cheese (boolean) - اختياري، القيمة الافتراضية false

    pepperoni (boolean) - اختياري، القيمة الافتراضية false

    mushrooms (boolean) - اختياري، القيمة الافتراضية false

    يجب أن يكون منشئ Pizza خاصاً (private) ويقبل فقط PizzaBuilder كمعامل له، مع نسخ جميع القيم من الباني إلى حقول البيتزا.

    قم بتضمين طريقة getDescription() التي تعيد سلسلة نصية بهذا التنسيق: [size] Pizza with: [toppings] حيث toppings هي قائمة مفصولة بفاصلة للإضافات التي قيمتها true وهي (Cheese، Pepperoni، Mushrooms). إذا لم يتم اختيار أي إضافات، يجب أن يقول جزء الإضافات ببساطة no toppings.

    قم بإنشاء فئة داخلية ثابتة (static inner class) باسم PizzaBuilder تحتوي على:

    • منشئ (constructor) يأخذ معامل size المطلوب
    • طرق cheese()، و pepperoni()، و mushrooms() حيث تقوم كل منها بضبط القيمة المنطقية الخاصة بها إلى true وتعيد this للسماح بالتسلسل (chaining)
    • طريقة build() تعيد كائن Pizza جديداً
  • Main.java: استعرض باني البيتزا الخاص بك أثناء العمل! ستتلقى أربعة مدخلات: حجم البيتزا (String)، وثلاث قيم yes/no (Strings) تشير إلى ما إذا كان سيتم إضافة الجبن، والببروني، والفطر على التوالي.

    قم بإنشاء PizzaBuilder بالحجم المعطى. ثم، بناءً على كل مدخل yes/no، قم بتسلسل طرق الإضافات المناسبة. إذا كان الإدخال "yes"، فاستدعِ طريقة الإضافة تلك؛ وإذا كان "no"، فتخطاها. أخيراً، استدعِ build() لإنشاء البيتزا الخاصة بك.

    اطبع نتيجة استدعاء getDescription() على البيتزا المكتملة.

ستتلقى أربعة مدخلات بالترتيب: الحجم (String)، إضافة الجبن (String: "yes" أو "no")، إضافة الببروني (String: "yes" أو "no")، إضافة الفطر (String: "yes" أو "no").

على سبيل المثال، مع المدخلات Large، و yes، و no، و yes، سيكون مخرجك: Large Pizza with: Cheese, Mushrooms

لاحظ كيف يسمح لك نمط Builder بإنشاء بيتزا بأي مزيج من الإضافات دون الحاجة إلى منشئات منفصلة لكل احتمال!

ورقة مرجعية

يُعد نمط البناء (Builder Pattern) نمط تصميم إنشائي لبناء كائنات معقدة تحتوي على العديد من المعلمات الاختيارية. فهو يتجنب المنشئات المتداخلة (telescoping constructors) وقوائم المعلمات الطويلة من خلال بناء الكائنات خطوة بخطوة.

الهيكل

يتكون النمط من:

  • فئة (class) تحتوي على منشئ خاص (private constructor) لا يقبل سوى كائن بناء (builder)
  • فئة بناء داخلية ثابتة (static inner Builder class) تقوم بإنشاء الكائن
  • طرق بناء (Builder methods) تُرجع this من أجل تسلسل الطرق (method chaining)
  • طريقة build() تقوم بإنشاء الكائن النهائي

مثال على التنفيذ

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);
        }
    }
}

الاستخدام مع تسلسل الطرق (Method Chaining)

User user = new User.UserBuilder("Alice", "alice@email.com")
    .age(25)
    .phone("555-1234")
    .build();

يُعد نمط البناء مثاليًا عندما تحتوي الكائنات على العديد من الحقول الاختيارية، مما يوفر كودًا قابلًا للقراءة والصيانة مقارنة بالمنشئات التي تحتوي على معلمات عديدة.

جرّب بنفسك

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: ربط طرق الإضافات (topping methods) بناءً على مدخلات yes/no
        // TODO: بناء البيتزا وطباعة وصفها
        
    }
}
quiz iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

جميع دروس Object Oriented Programming