CyStack logo
  • Sản phẩm & Dịch vụ
  • Giải pháp
  • Bảng giá
  • Công ty
  • Tài liệu
Vi

vi

Mục lục

Trang chủBlogComposition vs Inheritanc...
Java

Composition vs Inheritance trong OOP: So sánh, ví dụ và lý do nên chọn Composition

4 phút đọc09/09/2025
CyStack Author
Chris Pham

Technical Writer

0 lượt xem
Reading Time: 4 minutes

Composition vs Inheritance là một trong những câu hỏi phỏng vấn thường gặp. Bạn hẳn cũng từng nghe lời khuyên nên ưu tiên dùng Composition thay vì Inheritance.

Composition vs Inheritance trong OOP

Composition vs Inheritance

Cả Composition và Inheritance đều là các khái niệm trong lập trình hướng đối tượng. Chúng không gắn chặt với một ngôn ngữ lập trình cụ thể nào như Java. Trước khi đi vào so sánh việc sử dụng Composition so với Inheritance trong code, hãy cùng điểm qua định nghĩa ngắn gọn của từng khái niệm nhanh về chúng.

Composition

Composition là một kỹ thuật thiết kế trong lập trình hướng đối tượng để triển khai mối quan hệ has-a (có-một) giữa các đối tượng. Trong Java, Composition được thực hiện bằng cách sử dụng các biến instance của những object khác. Ví dụ: một Person có một Job (a Person has a Job) có thể được triển khai như sau trong lập trình hướng đối tượng với Java.

package com.journaldev.composition;

public class Job {
// variables, methods etc.
}
package com.journaldev.composition;

public class Person {

    //composition has-a relationship
    private Job job;

    //variables, methods, constructors etc. object-oriented

Inheritance là một kỹ thuật thiết kế trong lập trình hướng đối tượng để triển khai mối quan hệ is-a (là-một) giữa các đối tượng. Trong Java, Inheritance được thực hiện bằng cách sử dụng từ khóa extends. Ví dụ: mối quan hệ Cat is an Animal (Mèo là một Loài động vật) trong lập trình Java sẽ được triển khai như sau.

package com.journaldev.inheritance;
 
public class Animal {
// variables, methods etc.
}
package com.journaldev.inheritance;
 
public class Cat extends Animal{
}

Composition over Inheritance

Cả Composition và Inheritance đều giúp tái sử dụng code nhưng theo những cách tiếp cận khác nhau. Vậy nên chọn cách nào? Làm thế nào để so sánh giữa Composition và Inheritance? Hẳn bạn đã từng nghe lời khuyên trong lập trình là nên ưu tiên Composition hơn Inheritance. Hãy cùng xem một số lý do sẽ giúp bạn lựa chọn giữa hai kỹ thuật này.

  1. Inheritance tạo ra sự tightly coupled (gắn kết chặt chẽ), trong khi Composition mang tính loosely coupled (gắn kết lỏng lẻo, linh hoạt hơn). Giả sử chúng ta có các class bên dưới sử dụng Inheritance:
package com.journaldev.java.examples;

public class ClassA {

	public void foo(){	
	}
}

class ClassB extends ClassA{
	public void bar(){
		
	}
}

Để đơn giản, chúng ta đặt cả superclass và subclass trong cùng một package. Nhưng trên thực tế, chúng thường nằm ở các cơ sở mã khác nhau. Có thể có nhiều class mở rộng từ superclass ClassA. Một ví dụ rất phổ biến cho tình huống này là việc kế thừa từ class Exception. Bây giờ, giả sử phần triển khai (implementation) của ClassA được thay đổi như sau: một method mới là bar() được thêm vào.

package com.journaldev.java.examples;

public class ClassA {

	public void foo(){	
	}
	
	public int bar(){
		return 0;
	}
}

Ngay khi bạn bắt đầu sử dụng bản triển khai mới của ClassA, bạn sẽ gặp compile-time error trong ClassB với thông báo: The return type is incompatible with ClassA.bar() (kiểu trả về không tương thích với ClassA.bar()). Giải pháp là phải thay đổi method bar() ở superclass hoặc subclass để chúng tương thích với nhau. Tuy nhiên, nếu bạn sử dụng Composition thay vì Inheritance, bạn sẽ không bao giờ gặp vấn đề này. Một ví dụ đơn giản về cách triển khai ClassB bằng Composition có thể như sau:

class ClassB{
	ClassA classA = new ClassA();
	
	public void bar(){
		classA.foo();
		classA.bar();
	}
}
  1. Trong Inheritance, không có cơ chế kiểm soát truy cập, trong khi với composition, chúng ta có thể giới hạn quyền truy cập. Khi sử dụng Inheritance, tất cả các method của superclass đều được “phơi bày” cho những class khác có quyền truy cập vào subclass. Vì vậy, nếu trong superclass xuất hiện method mới hoặc có lỗ hổng bảo mật, thì subclass cũng sẽ trở nên dễ bị tấn công. Ngược lại, trong Composition, chúng ta có thể chọn những method nào sẽ được sử dụng. Điều này giúp Composition an toàn hơn so với Inheritance. Ví dụ: trong ClassB, chúng ta có thể chỉ cung cấp (expose) method foo() của ClassA cho các class khác bằng đoạn code như sau:
class ClassB {
	
	ClassA classA = new ClassA();
	
	public void foo(){
		classA.foo();
	}
	
	public void bar(){	
	}
	
}

Đây chính là một trong những ưu điểm lớn nhất của Composition so với Inheritance.

  1. Composition mang lại sự linh hoạt trong việc gọi các method, điều này đặc biệt hữu ích trong trường hợp có nhiều subclass. Ví dụ: giả sử chúng ta có tình huống sử dụng Inheritance như dưới đây:
abstract class Abs {
	abstract void foo();
}

public class ClassA extends Abs{

	public void foo(){	
	}
	
}

class ClassB extends Abs{
		
	public void foo(){
	}
	
}

class Test {
	
	ClassA a = new ClassA();
	ClassB b = new ClassB();

	public void test(){
		a.foo();
		b.foo();
	}
}

Vậy nếu có thêm nhiều subclass nữa thì sao? Liệu Composition có làm code trở nên rườm rà vì phải tạo một instance riêng cho từng subclass không? Câu trả lời là không, chúng ta hoàn toàn có thể viết lại class Test như ví dụ dưới đây:

class Test {
	Abs obj = null;
	
	Test1(Abs o){
		this.obj = o;
	}
	
	public void foo(){
		this.obj.foo();
	}

}

Điều này mang lại cho bạn sự linh hoạt để sử dụng bất kỳ subclass nào, tùy thuộc vào object được truyền vào trong constructor.

  1. Một lợi ích nữa của Composition so với Inheritance là về phạm vi kiểm thử. Với Composition, việc viết Unit Test trở nên dễ dàng hơn, vì chúng ta biết rõ mình đang sử dụng những method nào từ class khác. Do đó, ta có thể mock các method đó để kiểm thử. Trong khi đó, với Inheritance, ta phụ thuộc rất nhiều vào superclass và không biết chắc sẽ cần dùng đến method nào từ nó. Vì vậy, ta buộc phải kiểm tra tất cả các method của superclass. Đây là khối lượng công việc dư thừa và không cần thiết, vốn chỉ phát sinh vì sử dụng Inheritance.

Kết luận về Composition vs Inheritance. Bạn đã có đủ lý do để lựa chọn Composition thay vì Inheritance. Hãy chỉ sử dụng Inheritance khi bạn chắc chắn rằng superclass sẽ không thay đổi. Trong các trường hợp còn lại, hãy ưu tiên Composition để có được thiết kế linh hoạt, an toàn và dễ bảo trì hơn.

Về tác giả

Chris Pham
Chris PhamTechnical Writer

I have over 5 years of experience writing technical documentation for tech products, making them accessible and user-friendly. My focus is always on providing clear and precise information. @#@ Tôi đã có hơn 5 năm kinh nghiệm viết tài liệu kỹ thuật cho các sản phẩm công nghệ, giúp người dùng dễ dàng tiếp cận và sử dụng. Tôi luôn tập trung vào việc cung cấp thông tin chính xác và dễ hiểu.

Cập nhật thông tin mới nhấtNhận các thông tin mới nhất về mối đe dọa, báo cáo an ninh mạng từ CyStack về hòm thư điện tử của bạn

Thảo luận (0)

Đăng nhập để thảo luận

Bài viết liên quan