نمط 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 عند إنشاء كائنات تحتوي على العديد من المكونات الاختيارية، أو عندما تريد كود إنشاء سهل القراءة، أو عندما يجب أن تؤدي عملية الإنشاء نفسها إلى تمثيلات مختلفة.
التحدي
سهللنقم ببناء نظام 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: اجمع كل شيء معاً لبناء جهاز كمبيوتر مخصص.اقرأ أربعة مدخلات:
- طراز المعالج CPU (سلسلة نصية)
- مواصفات الذاكرة العشوائية RAM (سلسلة نصية)
- مواصفات التخزين Storage (سلسلة نصية)
- ما إذا كان سيتم تضمين الواي فاي:
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;
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس Object Oriented Programming
1أساسيات الـ OOP
الملفات الخارجيةبناء وتجميع (Compilation) لغة C++ملفات الـ Header وملفات الـ Sourceالـ Namespaces والـ Scopeمقدمة في الـ OOP في C++الـ Classes مقابل الـ Objectsالمؤشر 'this'الـ Methods (الدوال الأعضاء)الـ Attributes (بيانات الأعضاء)أساسيات الـ Ctors والـ Dtorsمراجعة - آلة حاسبة بسيطة4خصائص الـ Class
أعضاء الـ Instance مقابل الـ Staticدوال الـ Getters والـ Settersدوال الأعضاء الثابتة (Const)الكلمة المفتاحية Mutableالدوال والمتغيرات الساكنة (Static)الدوال والفئات الصديقة (Friend)مراجعة - مدير الحساب البنكي7الوراثة
الوراثة الأساسيةمستويات الوصول في الوراثةترتيب استدعاء الـ Ctor والـ Dtorإعادة تعريف الدوال (Method Overriding)الدوال الافتراضية والـ VTableالوراثة المتعددةالوراثة الافتراضيةمراجعة - هيكلية الموظفين10نظرة عامة على STL
نظرة عامة وفلسفة STLحاويات STLالـ Iteratorsخوارزميات STLالـ Functors وتعبيرات Lambdaمراجعة - تكرار الكلمات13أنماط التصميم - الجزء الأول
مقدمة في أنماط التصميمنمط Singletonنمط Factory و Abstract Factoryنمط Builderنمط Observerنمط Strategy2إدارة الذاكرة
ذاكرة Stack مقابل Heapالمؤشرات والمراجعالذاكرة الديناميكية (new/delete)المؤشرات الذكية في C++RAII في C++مراجعة - مدير المصفوفات الديناميكية5التغليف (Encapsulation)
محددات الوصول في C++محددات الوصول بشكل متعمقإخفاء المعلوماتStruct مقابل Classالأصناف المتداخلة والداخليةمراجعة - نظام سجلات الطلاب8تعدد الأشكال (Polymorphism)
تعدد الأشكال: وقت التجميع مقابل وقت التشغيلالتحميل الزائد للدوال (Function Overloading)مراجعة الدوال الافتراضية (Virtual Functions)الدوال الافتراضية البحتة (Pure Virtual Functions)الأصناف المجردة (Abstract Classes)تصميم الواجهات (Interface) في C++التحويل الديناميكي (Dynamic Casting) و RTTIملخص - حاسبة الأشكال11مفاهيم OOP المتقدمة
التركيب مقابل الوراثةالـ Mixins عبر CRTPنمط Pimplمحو النوع (Type Erasure)أصناف Enum والأنواع القويةمعالجة الاستثناءات في OOPتسلسلات الاستثناءات المخصصة14أنماط التصميم - الجزء الثاني
نمط الأمرنمط المحولنمط المزيننمط قالب الطريقةنمط الحالةنمط التركيبRAII كنمط3المنشئات والموادم
المنشئ الافتراضيالمنشئ ذو المعاملاتمنشئ النسخمنشئ النقلقوائم تهيئة المنشئالمنشئات المفوضةتعمق في الموادمقاعدة الثلاثة / الخمسة / الصفرمراجعة - فئة String6تحميل العوامل (Operator Overloading)
مقدمة في تحميل العواملتحميل العوامل الحسابيةتحميل عوامل المقارنةعوامل Streamتحميل عامل التعيينتحميل العوامل [] و ()عوامل تحويل النوعمراجعة - Matrix Class9القوالب
قوالب الدوالقوالب الأصنافتخصيص القوالبالقوالب المتغيرةأساسيات SFINAE و Type Traitsمراجعة - الحاويات العامة