مبادئ SOLID في لغة C++: من النظرية إلى التطبيق
SOLID هو اختصار لخمسة مبادئ أساسية في البرمجة كائنية التوجه، صاغها روبرت مارتن (العم بوب). في سياق لغة C++، تساعد هذه المبادئ في إنشاء كود مرن، قابل للصيانة، وقابل للاختبار. في هذه المقالة، سنشرح كل مبدأ مع أمثلة عملية بلغة C++.
1. مبدأ المسؤولية الواحدة (Single Responsibility Principle - SRP)
الجوهر: يجب أن يكون لكل class سبب واحد فقط للتغيير. بكلمات بسيطة — class يقوم بمهمة واحدة فقط.
مثال سيء (انتهاك SRP):
class Report {public: void generateReport() { /* توليد التقرير */ } void saveToFile(const std::string& filename) { /* الحفظ في ملف */ } void printReport() { /* طباعة التقرير */ }};هنا، class Report مسؤول عن التوليد، الحفظ، والطباعة — ثلاث مسؤوليات مختلفة.
مثال جيد (الالتزام بـ SRP):
class Report {public: std::string generate() { /* توليد التقرير */ return "report data"; }};
class ReportSaver {public: void save(const std::string& data, const std::string& filename) { // الحفظ في ملف }};
class ReportPrinter {public: void print(const std::string& data) { // طباعة التقرير }};الآن كل class لديه مسؤولية واحدة واضحة، مما يبسط عملية الاختبار والتعديل.
2. مبدأ الانفتاح/الإغلاق (Open-Closed Principle - OCP)
الجوهر: يجب أن تكون الـ classes مفتوحة للتمديد ولكن مغلقة للتعديل. يجب أن تكون قادراً على إضافة وظائف جديدة دون تغيير الكود الموجود.
مثال سيء:
enum class ShapeType { Circle, Rectangle };
class Shape {public: ShapeType type;};
class AreaCalculator {public: double calculateArea(const Shape& shape) { if (shape.type == ShapeType::Circle) { // حساب مساحة الدائرة return 3.14 * radius * radius; } else if (shape.type == ShapeType::Rectangle) { // حساب مساحة المستطيل return width * height; } return 0.0; }};عند إضافة شكل جديد (مثل المثلث)، سيتعين تعديل AreaCalculator.
مثال جيد (من خلال تعدد الأشكال):
class Shape {public: virtual double area() const = 0; virtual ~Shape() = default;};
class Circle : public Shape { double radius;public: explicit Circle(double r) : radius(r) {} double area() const override { return 3.14159 * radius * radius; }};
class Rectangle : public Shape { double width, height;public: Rectangle(double w, double h) : width(w), height(h) {} double area() const override { return width * height; }};
class AreaCalculator {public: double calculateArea(const Shape& shape) { return shape.area(); }};الآن لإضافة شكل جديد، يكفي إنشاء class وراثي جديد دون لمس AreaCalculator.
3. مبدأ الاستبدال ليسكوف (Liskov Substitution Principle - LSP)
الجوهر: يجب أن تكون كائنات الـ subclasses قابلة للاستبدال بكائنات الـ base class دون الإخلال بصحة البرنامج.
انتهاك كلاسيكي (مستطيل-مربع):
class Rectangle {protected: int width, height;public: void setWidth(int w) { width = w; } void setHeight(int h) { height = h; } int area() const { return width * height; }};
class Square : public Rectangle {public: void setWidth(int w) override { width = w; height