Kodax

مشروع OOP متكامل — OOP في C++

مشروع: نظام إدارة مكتبة

حان وقت جمع كل ما تعلمته في برنامج واحد. اقرأ الكود الكامل في قسم المثال، ثم ارجع إلى هذا الشرح لتفهم قرارات التصميم.

المتطلبات

- إدارة الكتب والأعضاء.

- استعارة الكتب وإرجاعها مع منع استعارة كتاب مُعار.

- البحث والتقارير.

خريطة الأصناف

Person (مجرد)          Book
  ├── Member             (العنوان، المؤلف، متاح؟)
  └── Librarian
Library: تملك الكتب والأعضاء (vector<unique_ptr<...>>)

قرارات التصميم ولماذا

| القرار | الدرس | السبب |

|---|---|---|

| Person بدالة افتراضية خالصة | التجريد | لا يوجد "شخص عام" في المكتبة؛ كل شخص إما عضو أو موظف |

| مدمّر Person افتراضي | تعدد الأشكال | الأشخاص يُحذفون عبر مؤشر للأب |

| بيانات Book خاصة + دوال borrow/returnBook | التغليف | القاعدة "لا يُعار كتاب مُعار" محمية داخل Book |

| Library تملك الكائنات بـ unique_ptr | إدارة الموارد / Rule of Zero | لا delete يدوي ولا تسرب، ولا حاجة لمدمّر مكتوب |

| Member يخزن معرفات/مؤشرات غير مالكة للكتب | الملكية | المكتبة هي المالك الوحيد؛ العضو "يشير" فقط |

خطوات العمل التي ننصح بها في مشاريعك

1. اكتب قائمة الأسماء في المتطلبات: الأسماء المرشحة لتكون أصنافاً (كتاب، عضو، مكتبة).

2. اكتب الأفعال: دوال مرشحة (استعارة، إرجاع، بحث).

3. حدد من يملك من: الملكية الواضحة تمنع معظم أخطاء الذاكرة.

4. حدد القواعد لكل صنف واحمها بالتغليف.

5. ابنِ خطوة خطوة وشغّل بعد كل خطوة.

مراجعة ذاتية

قبل التحسينات، أجب دون النظر للكود:

- لماذا لا يمكن كتابة Person p("x");؟

- ماذا سيحدث لو كان مدمّر Person غير افتراضي؟

- لماذا لا يحتاج Library مُنشئ نسخ مكتوباً؟ وهل يمكن نسخ Library أصلاً؟ (تلميح: unique_ptr غير قابل للنسخ)

تحسينات مقترحة (تمارين)

1. حد الاستعارة: العضو يستعير 3 كتب كحد أقصى؛ احمِ القاعدة داخل Member.

2. تواريخ الإرجاع: أضف عدد أيام الاستعارة واحسب الغرامة عند التأخير.

3. أنواع مواد: اجعل Item صنفاً مجرداً يرث منه Book و Magazine (المجلات لا تُعار) — وطبّق تعدد الأشكال في canBorrow().

4. عامل الطباعة: أضف operator<< لـ Book و Member.

5. البحث: ابحث بجزء من العنوان مع تجاهل حالة الأحرف.

بعد هذا المشروع أنت جاهز لدورة C++ المتقدم: القوالب و STL والنقل والاستثناءات والتزامن.

#include <iostream>
#include <vector>
#include <memory>
#include <algorithm>
using namespace std;

// ===== Base Classes =====
class Person {
protected:
    int id;
    string name;
    string phone;
    static int nextId;

public:
    Person(const string& n, const string& p) 
        : id(nextId++), name(n), phone(p) {}
    
    virtual void display() const = 0;
    virtual ~Person() = default;
    
    int getId() const { return id; }
    string getName() const { return name; }
};

int Person::nextId = 1;

// ===== Book Class =====
class Book {
private:
    string isbn;
    string title;
    string author;
    bool available;
    int borrowerId;

public:
    Book(const string& i, const string& t, const string& a)
        : isbn(i), title(t), author(a), available(true), borrowerId(0) {}
    
    // Getters
    string getISBN() const { return isbn; }
    string getTitle() const { return title; }
    string getAuthor() const { return author; }
    bool isAvailable() const { return available; }
    int getBorrowerId() const { return borrowerId; }
    
    // Operations
    void borrow(int memberId) {
        available = false;
        borrowerId = memberId;
    }
    
    void returnBook() {
        available = true;
        borrowerId = 0;
    }
    
    // Operator overloading
    friend ostream& operator<<(ostream& os, const Book& b) {
        os << "📖 " << b.title << " - " << b.author;
        os << " [" << (b.available ? "متاح ✅" : "مُعار ❌") << "]";
        return os;
    }
};

// ===== Member Classes =====
class Member : public Person {
private:
    vector<string> borrowedBooks;  // ISBNs
    static const int MAX_BOOKS = 3;

public:
    Member(const string& n, const string& p) : Person(n, p) {}
    
    bool canBorrow() const {
        return borrowedBooks.size() < MAX_BOOKS;
    }
    
    void addBook(const string& isbn) {
        borrowedBooks.push_back(isbn);
    }
    
    void removeBook(const string& isbn) {
        auto it = find(borrowedBooks.begin(), borrowedBooks.end(), isbn);
        if (it != borrowedBooks.end()) {
            borrowedBooks.erase(it);
        }
    }
    
    int getBorrowedCount() const { return borrowedBooks.size(); }
    
    void display() const override {
        cout << "👤 عضو #" << id << ": " << name << endl;
        cout << "   الهاتف: " << phone << endl;
        cout << "   الكتب المستعارة: " << borrowedBooks.size() << "/" << MAX_BOOKS << endl;
    }
};

class Librarian : public Person {
private:
    string employeeId;

public:
    Librarian(const string& n, const string& p, const string& empId)
        : Person(n, p), employeeId(empId) {}
    
    void display() const override {
        cout << "📚 أمين مكتبة #" << id << ": " << name << endl;
        cout << "   رقم الموظف: " << employeeId << endl;
    }
};

// ===== Library System =====
class Library {
private:
    string name;
    vector<unique_ptr<Book>> books;
    vector<unique_ptr<Member>> members;
    vector<unique_ptr<Librarian>> staff;

public:
    Library(const string& n) : name(n) {}
    
    // إضافة كتاب
    void addBook(const string& isbn, const string& title, const string& author) {
        books.push_back(make_unique<Book>(isbn, title, author));
        cout << "✅ تمت إضافة: " << title << endl;
    }
    
    // إضافة عضو
    int addMember(const string& name, const string& phone) {
        auto member = make_unique<Member>(name, phone);
        int id = member->getId();
        members.push_back(move(member));
        cout << "✅ تسجيل عضو جديد: " << name << " (ID: " << id << ")" << endl;
        return id;
    }
    
    // البحث عن كتاب
    Book* findBook(const string& isbn) {
        for (auto& book : books) {
            if (book->getISBN() == isbn) {
                return book.get();
            }
        }
        return nullptr;
    }
    
    // البحث عن عضو
    Member* findMember(int id) {
        for (auto& member : members) {
            if (member->getId() == id) {
                return member.get();
            }
        }
        return nullptr;
    }
    
    // استعارة كتاب
    bool borrowBook(int memberId, const string& isbn) {
        Member* member = findMember(memberId);
        Book* book = findBook(isbn);
        
        if (!member) {
            cout << "❌ العضو غير موجود" << endl;
            return false;
        }
        if (!book) {
            cout << "❌ الكتاب غير موجود" << endl;
            return false;
        }
        if (!book->isAvailable()) {
            cout << "❌ الكتاب غير متاح" << endl;
            return false;
        }
        if (!member->canBorrow()) {
            cout << "❌ وصلت للحد الأقصى من الاستعارة" << endl;
            return false;
        }
        
        book->borrow(memberId);
        member->addBook(isbn);
        cout << "✅ تم استعارة: " << book->getTitle() << endl;
        return true;
    }
    
    // إرجاع كتاب
    bool returnBook(int memberId, const string& isbn) {
        Member* member = findMember(memberId);
        Book* book = findBook(isbn);
        
        if (!member || !book) {
            cout << "❌ بيانات غير صحيحة" << endl;
            return false;
        }
        
        book->returnBook();
        member->removeBook(isbn);
        cout << "✅ تم الإرجاع: " << book->getTitle() << endl;
        return true;
    }
    
    // عرض جميع الكتب
    void displayBooks() const {
        cout << "\n📚 كتب " << name << endl;
        cout << string(40, '=') << endl;
        for (const auto& book : books) {
            cout << *book << endl;
        }
    }
    
    // عرض الأعضاء
    void displayMembers() const {
        cout << "\n👥 أعضاء المكتبة" << endl;
        cout << string(40, '=') << endl;
        for (const auto& member : members) {
            member->display();
            cout << endl;
        }
    }
    
    // إحصائيات
    void showStats() const {
        int available = count_if(books.begin(), books.end(),
            [](const auto& b) { return b->isAvailable(); });
        
        cout << "\n📊 إحصائيات" << endl;
        cout << "إجمالي الكتب: " << books.size() << endl;
        cout << "الكتب المتاحة: " << available << endl;
        cout << "الكتب المُعارة: " << (books.size() - available) << endl;
        cout << "عدد الأعضاء: " << members.size() << endl;
    }
};

int main() {
    Library library("مكتبة المعرفة");
    
    // إضافة كتب
    cout << "=== إضافة كتب ===" << endl;
    library.addBook("978-1", "تعلم C++", "أحمد محمد");
    library.addBook("978-2", "هياكل البيانات", "سارة علي");
    library.addBook("978-3", "الخوارزميات", "محمد خالد");
    
    // إضافة أعضاء
    cout << "\n=== تسجيل أعضاء ===" << endl;
    int member1 = library.addMember("علي", "0501234567");
    int member2 = library.addMember("فاطمة", "0509876543");
    
    // عرض الكتب
    library.displayBooks();
    
    // استعارة
    cout << "\n=== الاستعارة ===" << endl;
    library.borrowBook(member1, "978-1");
    library.borrowBook(member1, "978-2");
    library.borrowBook(member2, "978-3");
    
    // عرض بعد الاستعارة
    library.displayBooks();
    library.displayMembers();
    
    // إرجاع
    cout << "=== الإرجاع ===" << endl;
    library.returnBook(member1, "978-1");
    
    // الإحصائيات
    library.showStats();
    
    return 0;
}
اختبر فهمك