حقن التبعية (Dependency Injection) في C++: الحاويات والتطبيق العملي

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

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

ابدأ الدورة

حاوية Dependency Injection للغة C++: نظرة عامة وأمثلة عملية

\n\n

في التطوير الحديث بلغة C++، يتم بشكل متزايد تطبيق مبادئ Inversion of Control (IoC) و Dependency Injection (DI). تسمح هذه الأنماط بإنشاء كود ضعيف الاقتران، قابل للاختبار، وسهل التوسيع. على عكس اللغات ذات الذاكرة المُدارة (Java، C#)، لا تحتوي C++ على انعكاس (Reflection) مدمج، لذلك يتطلب تنفيذ حاويات DI هنا برمجة وصفية للقوالب (Template Metaprogramming) واستخدام المعايير الحديثة (C++11/14/17/20).

\n\n

في هذه المقالة، سنستعرض ثلاثة أساليب شائعة لحقن التبعيات في C++: المكتبات Boost.DI و Google Fruit و Kangaru، بالإضافة إلى كتابة حاوية بسيطة خاصة بنا لفهم الآلية.

\n\n

ما هو Dependency Injection؟

\n\n

Dependency Injection هي تقنية يحصل فيها الكائن على تبعياته من الخارج، بدلاً من إنشائها بنفسه. الأنواع الرئيسية لـ DI:

\n
    \n
  • Constructor Injection — يتم تمرير التبعيات عبر المُنشئ (Constructor).
  • \n
  • Setter Injection — يتم تعيين التبعيات عبر دوال الضبط (Setters).
  • \n
  • Interface Injection — يتم تمرير التبعيات عبر واجهة (Interface).
  • \n
\n\n

مثال بدون DI (اقتران قوي):

\n
class Logger {\npublic:\n    void log(const std::string& msg) { /* كتابة إلى ملف */ }\n};\n\nclass Service {\n    Logger logger; // تبعية قوية\npublic:\n    void doWork() { logger.log("Work done"); }\n};
\n\n

مثال مع DI (اقتران ضعيف):

\n
class ILogger {\npublic:\n    virtual ~ILogger() = default;\n    virtual void log(const std::string& msg) = 0;\n};\n\nclass ConsoleLogger : public ILogger {\npublic:\n    void log(const std::string& msg) override { std::cout << msg << std::endl; }\n};\n\nclass Service {\n    std::shared_ptr<ILogger> logger;\npublic:\n    explicit Service(std::shared_ptr<ILogger> l) : logger(std::move(l)) {}\n    void doWork() { logger->log("Work done"); }\n};
\n\n

نظرة عامة على حاويات DI للغة C++

\n\n

1. Boost.DI

\n

Boost.DI — واحدة من أشهر المكتبات. تستخدم قوالب C++14/17 لحل التبعيات تلقائياً. تدعم تعدد الأشكال (Polymorphism)، ونطاقات الرؤية (singleton, unique)، والتكوين المعياري (Modular Configuration).

\n\n

مثال على الاستخدام:

\n
#include <boost/di.hpp>\n#include <iostream>\n\nnamespace di = boost::di;\n\nclass IWriter {\npublic:\n    virtual ~IWriter() = default;\n    virtual void write(const std::string&) = 0;\n};\n\nclass ConsoleWriter : public IWriter {\npublic:\n    void write(const std::string& msg) override {\n        std::cout << msg << std::endl;\n    }\n};\n\nclass App {\n    std::shared_ptr<IWriter> writer;\npublic:\n    explicit App(std::shared_ptr<IWriter> w) : writer(std::move(w)) {}\n    void run() { writer->write("Hello from Boost.DI!"); }\n};\n\nint main() {\n    auto injector = di::make_injector(\n        di::bind<IWriter>.to<ConsoleWriter>()\n    );\n    auto app = injector.create<std::unique_ptr<App>>();\n    app->run();\n    return 0;\n}
\n\n

الإيجابيات: كتابة قوية (Strong Typing)، حمل زمن تشغيل ضئيل (Minimal Runtime Overhead)، دعم C++14/17.

\n

السلبيات: رسائل خطأ مترجم معقدة، زيادة وقت البناء (Build Time).

\n\n

2. Google Fruit

\n

Google Fruit — حاوية من Google، تعمل على C++11. تستخدم وحدات ماكرو (Macros) لتسجيل المكونات وتدعم الحقن عبر المُنشئ.

\n\n

مثال:

\n
#include <fruit/fruit.h>\n#include <iostream>\n\nclass IWriter {\npublic:\n    virtual void write(const std::string&) = 0;\n};\n\nclass ConsoleWriter : public IWriter {\npubli                    

توصيات