أنماط التصميم في لغة C++ مع أمثلة: تحليل شامل

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

مقدمة: لماذا نحتاج إلى أنماط التصميم في C++



أنماط التصميم (design patterns) هي حلول مجربة للمشاكل النمطية التي تظهر أثناء تطوير البرمجيات. في لغة C++، مع نظام الأنواع القوي، RAII، والوراثة المتعددة، تكتسب الأنماط مرونة خاصة. فهي تساعد في جعل الكود أكثر قابلية للقراءة، والصيانة، والتوسع.



في هذه المقالة، سننظر في 4 أنماط رئيسية من كتالوج GoF (Gang of Four): Singleton، Factory Method، Observer و Strategy. سيتم توضيح كل نمط بمثال كود حقيقي باستخدام C++17/20.



الأنماط الإنشائية: Singleton (المفرد)



Singleton يضمن وجود مثيل واحد فقط للفئة، ويوفر نقطة وصول عالمية إليه. في C++، يستخدم الأسلوب الحديث متغيرًا ثابتًا محليًا (آمن للخيوط منذ C++11).



مثال: مسجل التطبيق (Logger)



class Logger {public:    // حذف النسخ والتعيين    Logger(const Logger&) = delete;    Logger& operator=(const Logger&) = delete;

static Logger& getInstance() { static Logger instance; // آمن للخيوط منذ C++11 return instance; }

void log(const std::string& message) { std::lock_guard<std::mutex> lock(m_mutex); std::cout << "[LOG] " << message << std::endl; }

private: Logger() = default; // مُنشئ خاص ~Logger() = default; std::mutex m_mutex;};

// الاستخدامint main() { Logger::getInstance().log("تم تشغيل التطبيق"); Logger::getInstance().log("خطأ: الملف غير موجود"); return 0;}


الإيجابيات: ضمان التفرد، التهيئة البطيئة (lazy initialization)، أمان الخيوط.
السلبيات: يعقد الاختبار (حالة عامة)، ينتهك مبدأ المسؤولية الواحدة.



الأنماط الإنشائية: Factory Method (طريقة المصنع)



Factory Method يحدد واجهة لإنشاء كائن، لكنه يسمح للفئات الفرعية بتحديد الفئة التي سيتم إنشاء مثيل لها. في C++، غالبًا ما يتم تنفيذه من خلال الدوال الافتراضية والمؤشرات الذكية.



مثال: توليد أنواع مختلفة من المستندات



// منتج مجردclass Document {public:    virtual void open() = 0;    virtual void save() = 0;    virtual ~Document() = default;};

// منتجات محددةclass PDFDocument : public Document {public: void open() override { std::cout << "تم فتح PDF"; } void save() override { std::cout << "تم حفظ PDF"; }};

class WordDocument : public Document {public: void open() override { std::cout << "تم فتح Word"; } void save() override { std::cout << "تم حفظ Word"; }};

// المنشئ (Creator)class Application {public: virtual std::unique_ptr<Document> createDocument() = 0; virtual ~Application() = default;

void newDocument() { auto doc = createDocument(); doc->open(); // العمل مع المستند }};

// منشئون محددونclass PDFApplication : public Application {public: std::unique_ptr<Document> createDocument() override { return std::make_unique<PDFDocument>(); }};

class WordApplication : public Application {public: std::unique_ptr<Document> createDocument() override { return std::make_unique<WordDocument>(); }};

// الاستخدامint main() { std::unique_ptr<Application> app = std::make_unique<PDFApplication>(); app->newDocument(); // الإخراج: "تم فتح PDF" return 0;}


هذا النمط مثالي عندما تكون الأنواع الدقيقة للكائنات المراد إنشاؤها غير معروفة مسبقًا.



الأنماط السلوكية: Observer (المراقب)



المدونات

توصيات الكتب