مقدمة: لماذا نحتاج إلى أنماط التصميم في 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 (المراقب)
المدونات
توصيات الكتب
اقرأ أيضًا