Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Java

ความแตกต่างระหว่าง Association และ Aggregation ใน Java

Association และ Aggregation เป็นความสัมพันธ์ระหว่างคลาส (Class Relationships) ใน Object-Oriented Design ทั้งคู่เป็นรูปแบบของ "Has-a" relationship แตกต่างกันที่ "ความแข็งแกร่ง" และ "Lifecycle"

Association (การเชื่อมโยง)

ความสัมพันธ์ "Has-a" แบบทั่วไป - คลาสหนึ่งใช้/รู้จักอีกคลาสหนึ่ง

  • Object สามารถมีอยู่ได้แยกกัน (Independent lifecycle)
  • ไม่มี ownership - ไม่มีฝ่ายใดเป็นเจ้าของอีกฝ่าย
  • Multiplicity: 1-1, 1-*, *-* ได้ทั้งคู่
  • UML: เส้นทึบ (solid line) ระหว่างคลาส
// Association: Employee "has a" Address
// Address สามารถมีอยู่ได้โดยไม่ต้องมี Employee
// Employee ถูกลบ Address ยังคงอยู่ได้

class Employee {
    private String name;
    private Address communicationAddress;  // Reference to Address
    
    public Employee(String name, Address address) {
        this.name = name;
        this.communicationAddress = address;
    }
}

class Address {
    private String street;
    private String city;
    private String zipCode;
    
    public Address(String street, String city, String zipCode) {
        this.street = street;
        this.city = city;
        this.zipCode = zipCode;
    }
}

// Usage
Address addr = new Address("123 Main St", "Bangkok", "10110");
Employee emp = new Employee("John", addr);
// addr ยังใช้งานได้ต่อ แม้ emp จะถูก garbage collected

Aggregation (การรวม/การประกอบ - "Has-a" แบบมี Owner)

ความสัมพันธ์ "Has-a" แบบ Whole-Part โดย "Whole" (Container) เป็นเจ้าของ "Part" (Contained)

  • Weak ownership: Whole จัดการ lifecycle ของ Parts แต่ Parts สามารถมีอยู่ได้แยกต่างหาก
  • Part อาจถูก share ระหว่างหลาย Wholes ได้
  • Multiplicity: Whole 1 : Part * (มักเป็น Collection)
  • UML: เส้นทึบ + Empty Diamond (◇) ที่ฝั่ง Whole
// Aggregation: Department "has a" collection of Employees
// Department จัดการ employees แต่ Employee อาจย้าย department ได้
// หาก Department ถูกลบ Employee ยังคงอยู่ได้ (อาจย้ายไป dept อื่น)

class Department {
    private String name;
    private List<Employee> employees = new ArrayList<>();  // Collection of parts
    
    public Department(String name) {
        this.name = name;
    }
    
    public void addEmployee(Employee emp) {
        employees.add(emp);
        emp.setDepartment(this);  // Bidirectional link (optional)
    }
    
    public void removeEmployee(Employee emp) {
        employees.remove(emp);
        emp.setDepartment(null);
    }
}

class Employee {
    private String name;
    private Department department;  // Back reference (optional)
    
    public Employee(String name) { this.name = name; }
    
    public void setDepartment(Department dept) { this.department = dept; }
    public Department getDepartment() { return department; }
}

// Usage
Employee e1 = new Employee("Alice");
Employee e2 = new Employee("Bob");
Department dept = new Department("Engineering");
dept.addEmployee(e1);
dept.addEmployee(e2);
// e1, e2 ยังมีชีวิตอยู่ แม้ dept จะถูกลบ (ถ้ามี reference อื่น)

Composition (เพิ่มเติม - "Strong Aggregation")

รูปแบบสุดสุดของ Aggregation ที่ Part ไม่สามารถมีอยู่ได้โดยไม่มี Whole

  • Strong ownership: Whole สร้างและทำลาย Parts
  • Part ไม่สามารถ share ได้
  • UML: เส้นทึบ + Filled Diamond (◆) ที่ฝั่ง Whole
// Composition: House "has a" Rooms
// Room ไม่มีอยู่ได้โดยไม่มี House

class House {
    private List<Room> rooms = new ArrayList<>();
    
    public House() {
        // House สร้าง Rooms เอง
        rooms.add(new Room("Bedroom", 20));
        rooms.add(new Room("Kitchen", 15));
    }
    
    // ไม่มี setter สำหรับ rooms - ไม่ให้เพิ่ม/ล้างจากนอก
}

class Room {
    private String name;
    private double area;
    
    // Package-private constructor - สร้างได้แค่ใน House
    Room(String name, double area) {
        this.name = name;
        this.area = area;
    }
}

ตารางเปรียบเทียบ Association vs Aggregation vs Composition

คุณสมบัติ Association Aggregation Composition
Relationship Uses-a / Knows-a Has-a (Weak ownership) Has-a (Strong ownership)
Lifecycle Dependency Independent Part อาจอยู่ได้แยกจาก Whole Part ต้องอยู่กับ Whole เท่านั้น
Ownership ไม่มี Shared/Weak Exclusive/Strong
Part สามารถ Share ได้? ได้ (N-Ary association) ได้ ไม่ได้
Whole สร้าง Part? ไม่จำเป็น อาจสร้างหรือรับจากนอก ต้องสร้างเอง
Whole ทำลาย Part? ไม่ ไม่ (Part อาจย้ายไป Whole อื่น) ใช่ (เมื่อ Whole ตาย Part ตาย)
UML Notation ──────── ◇──────── ◆────────
Java Implementation Reference field Collection field (List/Set) Collection field + private constructor + no setters
Example Employee ↔ Address Department ↔ Employees House ↔ Rooms, Order ↔ OrderItems

Java Implementation Patterns

Association (Bidirectional)

class Student {
    private String name;
    private Course course;  // Single reference
    
    public void enroll(Course c) {
        this.course = c;
        c.addStudent(this);  // Maintain bidirectional consistency
    }
}

class Course {
    private List<Student> students = new ArrayList<>();
    public void addStudent(Student s) { students.add(s); }
}

Aggregation (Department-Employee)

class Department {
    private List<Employee> employees = new ArrayList<>();
    
    public void addEmployee(Employee e) {
        if (!employees.contains(e)) {
            employees.add(e);
            e.setDepartment(this);
        }
    }
}

Composition (Order-OrderItem)

class Order {
    private List<OrderItem> items = new ArrayList<>();
    
    public void addItem(Product product, int qty) {
        // Order สร้าง OrderItem เอง - ไม่อนุญาตสร้างจากนอก
        items.add(new OrderItem(this, product, qty));
    }
    
    // ไม่มี setItems(), ไม่มี public OrderItem constructor
}

class OrderItem {
    private final Order order;  // final - set ครั้งเดียวตอนสร้าง
    private final Product product;
    private int quantity;
    
    // Package-private - ใช้ได้แค่ใน package เดียวกับ Order
    OrderItem(Order order, Product product, int quantity) {
        this.order = order;
        this.product = product;
        this.quantity = quantity;
    }
}

Best Practices

  • ใช้ Composition over Inheritance (GoF) - Composition ให้ flexibility มากกว่า
  • เลือก Association เมื่อ objects มีชีวิตอยู่แยกกันได้จริง (เช่น Customer - Address)
  • เลือก Aggregation เมื่อเป็น Whole-Part แต่ Part reusable (เช่น Library - Books)
  • เลือก Composition เมื่อ Part ไม่มีความหมายโดยลำพัง (เช่น Order - OrderItem, House - Room)
  • ใน Java: ใช้ final fields, private constructors, defensive copying เพื่อ enforce ownership