نمط Builder
جزء من قسم البرمجة كائنية التوجه في رحلة C++ على Coddy. الدرس 93 من 104.
يفصل نمط Builder بين إنشاء كائن معقد وتمثيله، مما يتيح لك إنشاء تكوينات مختلفة خطوة بخطوة. ويكون هذا مفيدًا بشكل خاص عندما يحتوي الكائن على العديد من المعلمات الاختيارية أو يتطلب تسلسل إنشاء محددًا.
بدلاً من مُنشئ يحتوي على العديد من المعلمات (مما يجعله مربكًا)، يوفّر Builder أساليب واضحة ومُسمّاة لكل خيار من خيارات التكوين:
#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 مرجعًا إلى builder (return *this)، مما يتيح chaining للطرق من أجل واجهة سلسة. تُنهي طريقة build() العملية وتعيد الكائن المُنشأ.
استخدم Builder عند إنشاء كائنات تحتوي على العديد من المكوّنات الاختيارية، أو عندما تريد كود إنشاء مقروءًا، أو عندما يجب أن تنشئ عملية الإنشاء نفسها تمثيلات مختلفة.
التحدي
سهللنُنشئ نظام Computer Builder يتيح للمستخدمين تهيئة أجهزة كمبيوتر مخصصة خطوةً بخطوة. هذا سيناريو مثالي لنمط Builder: تحتوي أجهزة الكمبيوتر على العديد من المكونات الاختيارية، ونريد طريقة نظيفة وسهلة القراءة لتجميع تهيئات مختلفة.
ستنظّم كودك عبر ثلاثة ملفات:
Computer.h: عرّف فئة المنتج التي تمثّل جهاز كمبيوتر مهيأً بالكامل.يجب أن تخزّن فئة
Computerهذه المكونات كأعضاء خاصة:cpu(سلسلة نصية)،ram(سلسلة نصية)،storage(سلسلة نصية)،gpu(سلسلة نصية)، وhasWifi(قيمة منطقية). هيّئhasWifiإلىfalseوالسلاسل النصية إلى قيم فارغة افتراضيًا.أضف طريقة عامة تُسمّى
showSpecs()وتعرض تهيئة جهاز الكمبيوتر. لكل مكوّن تم تعيينه (أي لكل سلسلة نصية غير فارغة)، اطبعه في سطر مستقل. يجب طباعة إمكانية الاتصال بشبكة wifi فقط إذا كانت مفعّلة.ComputerBuilder.h: أنشئ فئة builder التي تبني أجهزة الكمبيوتر باستخدام واجهة سلسة.يجب أن تحتوي فئة
ComputerBuilderعلى عضو خاص من نوعComputerتعمل على بنائه. Implement هذه الطرق، بحيث تعيد كل منها مرجعًا إلى builder لتمكينchainingبين الطرق:setCPU(const std::string& cpu)setRAM(const std::string& ram)setStorage(const std::string& storage)setGPU(const std::string& gpu)addWifi(): enables إمكانية الاتصال بشبكة wifi
Also Implement طريقة
build()تعيد كائنComputerالمكتمل وتعيد ضبط builder لإتاحة إعادة استخدامه.main.cpp: اجمع كل شيء لبناء جهاز كمبيوتر مخصص.اقرأ أربعة inputs:
- طراز CPU (سلسلة نصية)
- مواصفات RAM (سلسلة نصية)
- مواصفات التخزين (سلسلة نصية)
- ما إذا كان ينبغي include wifi:
yesأوno
استخدم
ComputerBuilderلبناء جهاز كمبيوتر باستخدام CPU وRAM والتخزين المقدمة. إذا كانت قيمة wifi هيyes، فاستدعِ أيضًاaddWifi(). لاحظ أنه لم يتم تحديد GPU في هذه التهيئة: يجب أن يتعامل builder مع المكونات الاختيارية بسلاسة.بعد البناء، استدعِ
showSpecs()على جهاز الكمبيوتر الناتج لعرض تهيئته.
يجب أن تُخرج طريقة showSpecs() البيانات بهذا التنسيق (مع عرض المكونات التي تم تعيينها فقط):
CPU: [value]
RAM: [value]
Storage: [value]
GPU: [value]
Wifi: Enabledعلى سبيل المثال، باستخدام inputs هي Intel i7-12700K و32GB DDR5 و1TB NVMe SSD وyes:
CPU: Intel i7-12700K
RAM: 32GB DDR5
Storage: 1TB NVMe SSD
Wifi: Enabledوباستخدام inputs هي AMD Ryzen 5 5600X و16GB DDR4 و512GB SSD وno:
CPU: AMD Ryzen 5 5600X
RAM: 16GB DDR4
Storage: 512GB SSDلاحظ كيف يجعل نمط Builder عملية البناء مقروءة ومرنة. يمكنك بسهولة إضافة المكونات أو تخطيها، كما أن chaining بين الطرق ينشئ كودًا واضحًا وموضحًا لذاته. لا يظهر سطر GPU لأننا لم نعيّنه مطلقًا، مما يوضح كيفية تعامل builders مع المكونات الاختيارية بصورة طبيعية.
جرّب بنفسك
#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: استخدم تسلسل الطرق لتعيين CPU و RAM و storage
// TODO: إذا كان wifiChoice هو "yes"، استدعِ أيضاً addWifi()
// TODO: استدعِ build() للحصول على كائن Computer
// TODO: استدعِ showSpecs() على الحاسوب المُنشأ لعرض التكوين
return 0;
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس البرمجة كائنية التوجه
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مراجعة - الحاويات العامةتدرّب بنفسك: مترجم C++ عبر الإنترنت