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

نمط Builder

جزء من قسم Object Oriented Programming في رحلة C++ على Coddy — الدرس 93 من 104.

يفصل نمط البناء (Builder pattern) عملية إنشاء كائن معقد عن تمثيله، مما يسمح لك بإنشاء تكوينات مختلفة خطوة بخطوة. هذا مفيد بشكل خاص عندما يحتوي الكائن على العديد من المعلمات الاختيارية أو يتطلب تسلسلاً محدداً للبناء.

بدلاً من استخدام منشئ (constructor) يحتوي على العديد من المعاملات (والذي قد يصبح مربكاً)، يوفر نمط البناء (Builder) دوالاً (methods) واضحة ومسماة لكل خيار من خيارات التكوين:

#include <iostream>
#include <string>

class Pizza {
public:
    std::string dough;
    std::string sauce;
    std::string topping;
    bool cheese;
    
    void describe() const {
        std::cout << dough << " dough, " << sauce << " sauce, "
                  << topping << (cheese ? ", with cheese" : "") << "\n";
    }
};

class PizzaBuilder {
private:
    Pizza pizza;
    
public:
    PizzaBuilder& setDough(const std::string& d) {
        pizza.dough = d;
        return *this;
    }
    
    PizzaBuilder& setSauce(const std::string& s) {
        pizza.sauce = s;
        return *this;
    }
    
    PizzaBuilder& setTopping(const std::string& t) {
        pizza.topping = t;
        return *this;
    }
    
    PizzaBuilder& addCheese() {
        pizza.cheese = true;
        return *this;
    }
    
    Pizza build() { return pizza; }
};

int main() {
    Pizza margherita = PizzaBuilder()
        .setDough("thin")
        .setSauce("tomato")
        .setTopping("basil")
        .addCheese()
        .build();
    
    margherita.describe();
}

تعيد كل طريقة تعيين (setter method) مرجعاً إلى الباني (return *this)، مما يتيح ربط الطرق (method chaining) للحصول على واجهة سلسة (fluent interface). تقوم الطريقة build() بإنهاء وإرجاع الكائن الذي تم إنشاؤه.

استخدم نمط Builder عند إنشاء كائنات تحتوي على العديد من المكونات الاختيارية، أو عندما تريد كود إنشاء سهل القراءة، أو عندما يجب أن تؤدي عملية الإنشاء نفسها إلى تمثيلات مختلفة.

challenge icon

التحدي

سهل

لنقم ببناء نظام Computer Builder يتيح للمستخدمين تكوين أجهزة كمبيوتر مخصصة خطوة بخطوة. هذا سيناريو مثالي لنمط Builder—فأجهزة الكمبيوتر تحتوي على العديد من المكونات الاختيارية، ونريد طريقة نظيفة وقابلة للقراءة لتجميع تكوينات مختلفة.

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

  • Computer.h: حدد فئة المنتج (product class) التي تمثل جهاز كمبيوتر تم تكوينه بالكامل.

    يجب أن تقوم فئة Computer بتخزين هذه المكونات كأعضاء خاصين (private members): cpu (سلسلة نصية)، ram (سلسلة نصية)، storage (سلسلة نصية)، gpu (سلسلة نصية)، و hasWifi (قيمة منطقية). قم بتهيئة hasWifi إلى false والسلاسل النصية لتكون فارغة بشكل افتراضي.

    أضف طريقة عامة (public method) تسمى showSpecs() تعرض تكوين الكمبيوتر. لكل مكون تم تعيينه (سلسلة نصية غير فارغة)، قم بطباعته في سطر خاص به. يجب طباعة إمكانية الواي فاي فقط إذا كانت مفعلة.

  • ComputerBuilder.h: أنشئ فئة البناء (builder class) التي تقوم بإنشاء أجهزة الكمبيوتر بواجهة سلسة (fluent interface).

    يجب أن تحتوي فئة ComputerBuilder على عضو Computer خاص تقوم ببنائه. قم بتنفيذ هذه الطرق، بحيث تعيد كل منها مرجعاً (reference) إلى الباني لتمكين ربط الطرق (method chaining):

    • setCPU(const std::string& cpu)
    • setRAM(const std::string& ram)
    • setStorage(const std::string& storage)
    • setGPU(const std::string& gpu)
    • addWifi() — لتفعيل إمكانية الواي فاي

    قم أيضاً بتنفيذ طريقة build() التي تعيد كائن Computer المكتمل وتعيد ضبط الباني لإمكانية إعادة استخدامه.

  • main.cpp: اجمع كل شيء معاً لبناء جهاز كمبيوتر مخصص.

    اقرأ أربعة مدخلات:

    1. طراز المعالج CPU (سلسلة نصية)
    2. مواصفات الذاكرة العشوائية RAM (سلسلة نصية)
    3. مواصفات التخزين Storage (سلسلة نصية)
    4. ما إذا كان سيتم تضمين الواي فاي: yes أو no

    استخدم ComputerBuilder لإنشاء جهاز كمبيوتر باستخدام المعالج والذاكرة العشوائية والتخزين المقدمة. إذا كان مدخل الواي فاي هو yes، فقم أيضاً باستدعاء addWifi(). لاحظ أنه لم يتم تحديد GPU في هذا التكوين—يجب أن يتعامل الباني مع المكونات الاختيارية بسلاسة.

    بعد البناء، استدعِ showSpecs() على جهاز الكمبيوتر الناتج لعرض تكوينه.

يجب أن تخرج طريقة showSpecs() بهذا التنسيق (مع إظهار المكونات التي تم تعيينها فقط):

CPU: [value]
RAM: [value]
Storage: [value]
GPU: [value]
Wifi: Enabled

على سبيل المثال، مع المدخلات Intel i7-12700K، 32GB DDR5، 1TB NVMe SSD، و yes:

CPU: Intel i7-12700K
RAM: 32GB DDR5
Storage: 1TB NVMe SSD
Wifi: Enabled

مع المدخلات AMD Ryzen 5 5600X، 16GB DDR4، 512GB SSD، و no:

CPU: AMD Ryzen 5 5600X
RAM: 16GB DDR4
Storage: 512GB SSD

لاحظ كيف يجعل نمط Builder عملية الإنشاء قابلة للقراءة ومرنة—يمكنك بسهولة إضافة أو تخطي المكونات، ويخلق ربط الطرق كوداً واضحاً ويوثق نفسه بنفسه. لا يظهر سطر GPU لأننا لم نقم بتعيينه أبداً، مما يوضح كيف تتعامل البناة مع المكونات الاختيارية بشكل طبيعي.

ورقة مرجعية

يفصل نمط الباني (Builder pattern) عملية بناء كائن معقد عن تمثيله، مما يسمح بالتهيئة خطوة بخطوة. إنه مفيد عندما يحتوي الكائن على العديد من المعلمات الاختيارية أو يتطلب تسلسلاً محدداً للبناء.

بدلاً من المنشئات (constructors) التي تحتوي على العديد من المعلمات، يوفر الباني (Builder) طرقاً (methods) واضحة ومسماة لكل خيار تهيئة:

class Pizza {
public:
    std::string dough;
    std::string sauce;
    std::string topping;
    bool cheese;
};

class PizzaBuilder {
private:
    Pizza pizza;
    
public:
    PizzaBuilder& setDough(const std::string& d) {
        pizza.dough = d;
        return *this;  // Enable method chaining
    }
    
    PizzaBuilder& setSauce(const std::string& s) {
        pizza.sauce = s;
        return *this;
    }
    
    PizzaBuilder& setTopping(const std::string& t) {
        pizza.topping = t;
        return *this;
    }
    
    PizzaBuilder& addCheese() {
        pizza.cheese = true;
        return *this;
    }
    
    Pizza build() { return pizza; }
};

// Usage with method chaining
Pizza margherita = PizzaBuilder()
    .setDough("thin")
    .setSauce("tomato")
    .setTopping("basil")
    .addCheese()
    .build();

تعيد كل طريقة تعيين (setter method) القيمة return *this لتمكين تسلسل الطرق (method chaining) من أجل واجهة سلسة. تقوم الطريقة build() بإنهاء وإرجاع الكائن الذي تم بناؤه.

استخدم نمط الباني (Builder) عند بناء كائنات تحتوي على العديد من المكونات الاختيارية، أو عندما تريد كود بناء سهل القراءة، أو عندما يجب أن تؤدي عملية البناء نفسها إلى إنشاء تمثيلات مختلفة.

جرّب بنفسك

#include <iostream>
#include <string>
#include "ComputerBuilder.h"

using namespace std;

int main() {
    // قراءة المدخلات
    string cpu, ram, storage, wifiChoice;
    getline(cin, cpu);
    getline(cin, ram);
    getline(cin, storage);
    getline(cin, wifiChoice);

    // TODO: إنشاء مثيل من ComputerBuilder
    
    // TODO: استخدم تسلسل الدوال (method chaining) لضبط CPU و RAM و storage
    
    // TODO: إذا كانت wifiChoice هي "yes"، قم أيضاً باستدعاء addWifi()
    
    // TODO: استدعِ build() للحصول على كائن Computer
    
    // TODO: استدعِ showSpecs() على الكمبيوتر الذي تم بناؤه لعرض الإعدادات

    return 0;
}
quiz iconاختبر نفسك

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

جميع دروس Object Oriented Programming