Menu
Coddy logo textTech

אגרגציה מול הרכבה

חלק מהיחידה תכנות מונחה עצמים במסלול ה-Java של Coddy. שיעור 48 מתוך 87.

גם אגרגציה וגם קומפוזיציה הן צורות של קשרי „יש-לו”, אך הן נבדלות בהיבט מכריע אחד: בעלות ותלות במחזור החיים.

בהרכבה, האובייקט המוכל אינו יכול להתקיים באופן עצמאי מהמכיל. כשהמכיל מושמד, גם החלקים שלו מושמדים. חשבו על 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();  // House יוצרת את החדרים והם בבעלותה
        }
    }
}

בצבירה, האובייקט הכלול יכול להתקיים באופן עצמאי. המכולה משתמשת באובייקט אך אינה שולטת במחזור החיים שלו. חשבו על Team ועל אובייקטי Player שלו: שחקנים קיימים גם ללא קבוצה:

class Team {
    private List<Player> players;
    
    public Team() {
        players = new ArrayList<>();
    }
    
    public void addPlayer(Player player) {
        players.add(player);  // Team משתמשת בשחקנים קיימים
    }
}

ההבדל העיקרי: בהרכבה, המכל יוצר את החלקים שלו באופן פנימי. בצבירה, אובייקטים מועברים פנימה מבחוץ. כאשר Team נמחקת, האובייקטים מסוג Player עדיין קיימים. כאשר House נמחקת, גם האובייקטים מסוג Room שלה נעלמים.

challenge icon

אתגר

קל

בואו נבנה מערכת קורסים אוניברסיטאית המדגימה גם צבירה וגם הרכבה. תראו איך Course מכילה את אובייקטי ה־Lecture שלה (הרכבה), בעוד שהיא רק מפנה לאובייקטי Professor שקיימים באופן עצמאי (צבירה).

תארגנו את הקוד שלכם בארבעה קבצים:

  • Professor.java: צרו מחלקה המייצגת פרופסור שיכול להתקיים באופן עצמאי, ללא תלות בקורס כלשהו. למחלקה Professor יש שני שדות פרטיים: name (String) ו־department (String). כללו בנאי לאתחול שני השדות ומתודות 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 דקות. יצירה פנימית זו מדגימה הרכבה.

    הוסיפו מתודת getInfo() שמחזירה String בן כמה שורות:

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

    הוסיפו גם מתודת listLectures() שמחזירה String שבו ה־toString() של כל הרצאה מופיע בשורה נפרדת.

  • Main.java: חברו את כל החלקים! תקבלו ארבעה קלטים: שם הפרופסור (String), המחלקה של הפרופסור (String), שם הקורס (String) ומספר ההרצאות (int).

    תחילה, צרו Professor עם השם והמחלקה שסופקו. הפרופסור הזה קיים באופן עצמאי. לאחר מכן, צרו Course והעבירו אליו את שם הקורס, את הפרופסור (צבירה) ואת מספר ההרצאות (הקורס ייצור את ההרצאות שלו באופן פנימי — הרכבה).

    הדפיסו את התוצאה של getInfo(), לאחר מכן הדפיסו שורה ריקה, ואז הדפיסו את התוצאה של listLectures().

תקבלו ארבעה קלטים לפי הסדר: שם הפרופסור, המחלקה, שם הקורס ומספר ההרצאות.

שימו לב להבדל המרכזי: ה־Professor נוצר מחוץ ל־Course ומועבר אליו (צבירה: הפרופסור יכול ללמד קורסים אחרים או להתקיים גם בלי הקורס הזה). ה־Lectures נוצרות בתוך הבנאי של Course (הרכבה). הן שייכות בלעדית לקורס הזה ולא היו קיימות בלעדיו.

נסו בעצמכם

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 (קיים באופן עצמאי - אגרגציה)
        
        // TODO: צרו אובייקט Course והעבירו אליו את המרצה (אגרגציה)
        // הקורס ייצור את ההרצאות שלו בעצמו באופן פנימי (קומפוזיציה)
        
        // TODO: הדפיסו את התוצאה של getInfo()
        
        // TODO: הדפיסו שורה ריקה
        
        // TODO: הדפיסו את התוצאה של listLectures()
        
    }
}
quiz iconבחנו את עצמכם

השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.

כל השיעורים ביחידה תכנות מונחה עצמים

תרגלו בעצמכם: קומפיילר Java אונליין