Menu
Coddy logo textTech
flag Ar iconالعربيةdown icon

الـ Aggregation مقابل الـ Composition

جزء من قسم Object Oriented Programming في رحلة Java على Coddy — الدرس 48 من 87.

يعد كل من التجميع (aggregation) والتركيب (composition) شكلين من علاقات "has-a"، ولكنهما يختلفان في جانب جوهري واحد: الملكية والتبعية في دورة الحياة.

في التركيب (composition)، لا يمكن للكائن المحتوى أن يوجد بشكل مستقل عن الحاوية. فعندما يتم تدمير الحاوية، يتم تدمير أجزائها أيضًا. فكر في كائن House وكائنات Room الخاصة به—فالغرف لا توجد بدون المنزل:

class House {
    private Room[] rooms;
    
    public House(int numRooms) {
        rooms = new Room[numRooms];
        for (int i = 0; i < numRooms; i++) {
            rooms[i] = new Room();  // المنزل ينشئ الغرف ويمتلكها
        }
    }
}

في عملية التجميع (aggregation)، يمكن للكائن المضمن أن يوجد بشكل مستقل. تستخدم الحاوية الكائن ولكنها لا تتحكم في دورة حياته. فكر في Team وكائناته من نوع Player—اللاعبون موجودون حتى بدون فريق:

class Team {
    private List<Player> players;
    
    public Team() {
        players = new ArrayList<>();
    }
    
    public void addPlayer(Player player) {
        players.add(player);  // الفريق يستخدم اللاعبين الحاليين
    }
}

التمييز الأساسي: في التكوين (composition)، تقوم الحاوية بإنشاء أجزائها داخلياً. أما في التجميع (aggregation)، فيتم تمرير الكائنات من الخارج. عندما يتم حذف Team، تظل كائنات Player موجودة. وعندما يتم حذف House، تختفي كائنات Room الخاصة به أيضاً.

challenge icon

التحدي

سهل

لنقم ببناء نظام دورات جامعية يوضح كلاً من التجميع (aggregation) والتركيب (composition). سترى كيف تمتلك Course كائنات Lecture الخاصة بها (تركيب)، بينما تشير فقط إلى كائنات Professor التي توجد بشكل مستقل (تجميع).

ستقوم بتنظيم الكود الخاص بك عبر أربعة ملفات:

  • Professor.java: قم بإنشاء فئة تمثل أستاذاً يمكنه التواجد بشكل مستقل عن أي دورة تدريبية. لدى Professor حقلان خاصان: name (String) و department (String). قم بتضمين منشئ (constructor) لتهيئة كلا الحقلين وطرق getter لكل منهما. قم بإعادة كتابة toString() لتعيد: Prof. [name] ([department])
  • Lecture.java: قم بإنشاء فئة تمثل محاضرة لا يكون لها معنى إلا داخل دورة تدريبية. لدى Lecture حقلان خاصان: topic (String) و durationMinutes (int). قم بتضمين منشئ وطرق getter. قم بإعادة كتابة toString() لتعيد: Lecture: [topic] ([durationMinutes] min)
  • Course.java: هذا هو المكان الذي ستوضح فيه كلتا العلاقتين! لدى Course ثلاثة حقول خاصة: title (String)، و professor (Professor - تجميع)، و lectures (مصفوفة من كائنات Lecture - تركيب).

    يأخذ المنشئ عنوان الدورة، وكائن Professor (يتم تمريره من الخارج - تجميع)، وعدد المحاضرات. داخل المنشئ، قم بإنشاء مصفوفة Lecture واملأها بكائنات Lecture جديدة. لكل محاضرة عند الفهرس i، قم بإنشائها بموضوع "Topic " + (i + 1) ومدة 45 دقيقة. يوضح هذا الإنشاء الداخلي مفهوم التركيب (composition).

    أضف طريقة getInfo() التي تعيد سلسلة نصية (String) متعددة الأسطر:

    Course: [title]
    Instructor: [professor.toString()]
    Lectures: [number of lectures]

    أضف أيضاً طريقة listLectures() التي تعيد سلسلة نصية مع toString() الخاصة بكل محاضرة في سطر مستقل.

  • Main.java: اجمع كل شيء معاً! ستتلقى أربعة مدخلات: اسم الأستاذ (String)، قسم الأستاذ (String)، عنوان الدورة (String)، وعدد المحاضرات (int).

    أولاً، قم بإنشاء Professor بالاسم والقسم المعطيين—هذا الأستاذ موجود بشكل مستقل. ثم قم بإنشاء Course، مع تمرير العنوان، والأستاذ (تجميع)، وعدد المحاضرات (ستقوم الدورة بإنشاء محاضراتها الخاصة داخلياً - تركيب).

    اطبع نتيجة getInfo()، ثم اطبع سطراً فارغاً، ثم اطبع نتيجة listLectures().

ستتلقى أربعة مدخلات بالترتيب: اسم الأستاذ، القسم، عنوان الدورة، وعدد المحاضرات.

لاحظ الفرق الجوهري: يتم إنشاء Professor في الخارج وتمريره إلى Course (تجميع—يمكن للأستاذ تدريس دورات أخرى أو التواجد بدون هذه الدورة). يتم إنشاء Lectures داخل منشئ Course (تركيب—فهي تنتمي حصرياً لهذه الدورة ولن توجد بدونها).

ورقة مرجعية

كلاً من التجميع (aggregation) و التكوين (composition) هما علاقات من نوع "has-a" تختلف في الملكية والتبعية في دورة الحياة.

التكوين (Composition): لا يمكن للكائن المحتوى أن يوجد بشكل مستقل عن الحاوية. عندما يتم تدمير الحاوية، يتم تدمير أجزائها أيضاً. تقوم الحاوية بإنشاء أجزائها داخلياً.

class House {
    private Room[] rooms;
    
    public House(int numRooms) {
        rooms = new Room[numRooms];
        for (int i = 0; i < numRooms; i++) {
            rooms[i] = new Room();  // المنزل ينشئ الغرف ويمتلكها
        }
    }
}

التجميع (Aggregation): يمكن للكائن المحتوى أن يوجد بشكل مستقل. تستخدم الحاوية الكائن ولكنها لا تتحكم في دورة حياته. يتم تمرير الكائنات من الخارج.

class Team {
    private List<Player> players;
    
    public Team() {
        players = new ArrayList<>();
    }
    
    public void addPlayer(Player player) {
        players.add(player);  // الفريق يستخدم لاعبين موجودين مسبقاً
    }
}

الفرق الجوهري: عند حذف الحاوية، تظل الكائنات المجمعة (aggregated) موجودة، بينما يتم تدمير الكائنات المكونة (composed).

جرّب بنفسك

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // قراءة المدخلات
        String professorName = scanner.nextLine();
        String department = scanner.nextLine();
        String courseTitle = scanner.nextLine();
        int numberOfLectures = scanner.nextInt();
        
        // TODO: إنشاء كائن Professor (موجود بشكل مستقل - تجميع/aggregation)
        
        // TODO: إنشاء كائن Course، مع تمرير الأستاذ (تجميع/aggregation)
        // سيقوم الكورس بإنشاء المحاضرات الخاصة به داخلياً (تكوين/composition)
        
        // TODO: طباعة نتيجة getInfo()
        
        // TODO: طباعة سطر فارغ
        
        // TODO: طباعة نتيجة listLectures()
        
    }
}
quiz iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

جميع دروس Object Oriented Programming