أنماط التصميم في لغة C++ مع أمثلة: من الألف إلى الياء
أنماط التصميم (design patterns) هي حلول مثبتة للمشكلات النمطية التي تظهر أثناء تطوير البرمجيات. بالنسبة للغة C++، تعتبر هذه القوالب مهمة بشكل خاص، لأن اللغة تجمع بين البرمجة كائنية التوجه والبرمجة العامة والبرمجة منخفضة المستوى. في هذه المقالة، سنشرح أنماط التصميم الرئيسية في لغة C++ مع أمثلة كود ستساعدك على كتابة كود أكثر مرونة وقابلية لإعادة الاستخدام والصيانة.
سنستعرض ثلاث فئات رئيسية من الأنماط وفقًا لتصنيف GoF (Gang of Four): الأنماط الإنشائية والهيكلية والسلوكية. سيتم توضيح كل نمط بمثال واقعي بلغة C++.
1. الأنماط الإنشائية (Creational Patterns)
تعمل الأنماط الإنشائية على تجريد عملية إنشاء الكائنات، مما يجعل النظام مستقلاً عن كيفية إنشاء الكائنات وتركيبها وتمثيلها.
1.1. Singleton (المفرد)
يضمن Singleton أن يكون للفصل مثيل واحد فقط، ويوفر نقطة وصول عالمية إليه. في لغة C++، غالبًا ما يتم تنفيذه من خلال كائن محلي ثابت (آمن للخيوط منذ C++11).
class Logger {public: static Logger& getInstance() { static Logger instance; // تهيئة آمنة للخيوط return instance; }
void log(const std::string& message) { std::cout << "[LOG] " << message << std::endl; }
private: Logger() = default; Logger(const Logger&) = delete; Logger& operator=(const Logger&) = delete;};
// الاستخدامint main() { Logger::getInstance().log("تم تشغيل التطبيق"); return 0;}متى تستخدم: إدارة التكوين، تجمعات الخيوط، أنظمة التسجيل.
1.2. Factory Method (طريقة المصنع)
يحدد Factory Method واجهة لإنشاء كائن، لكنه يسمح للفئات الفرعية بتحديد الفئة التي سيتم إنشاء مثيل لها.
class Product {public: virtual void use() = 0; virtual ~Product() = default;};
class ConcreteProductA : public Product {public: void use() override { std::cout << "المنتج A" << std::endl; }};
class ConcreteProductB : public Product {public: void use() override { std::cout << "المنتج B" << std::endl; }};
class Creator {public: virtual Product* createProduct() = 0; void someOperation() { Product* p = createProduct(); p->use(); delete p; } virtual ~Creator() = default;};
class CreatorA : public Creator {public: Product* createProduct() override { return new ConcreteProductA(); }};
class CreatorB : public Creator {public: Product* createProduct() override { return new ConcreteProductB(); }};متى تستخدم: عندما لا يعرف الفصل أي كائنات من الفئات الفرعية يحتاج إلى إنشائها.
2. الأنماط الهيكلية (Structural Patterns)
تصف الأنماط الهيكلية كيف يمكن دمج الفئات والكائنات في هياكل أكبر، مع الحفاظ على المرونة والكفاءة.
2.1. Adapter (المهايئ)
يسمح Adapter للكائنات ذات الواجهات غير المتوافقة بالعمل معًا. في لغة C++، غالبًا ما يتم تنفيذه من خلال الوراثة أو التركيب.
// الواجهة المستهدفةclass Target {public: virtual void request() const { std::cout << "طلب عادي" << std::endl; } virtual ~Target() = default;};
// الفئة القابلة للتكييفclass Adaptee {public: void specificRequest() const { std::cout << "طلب محدد" << std::endl; }};
// المهايئ (من خلال التركيب)class Adapter : public Target {private: Adaptee* adaptee_;public: Adapter(Adaptee* a) : adaptee_(a) {} void request() const override { adaptee_->specificRequest(); }};