Interface là một bản hợp đồng quy định những phương thức mà lớp triển khai phải cài đặt, còn cách cài đặt cụ thể do lớp đó tự quyết. Interface mô tả một đối tượng làm được gì, không mô tả làm như thế nào.
Tài liệu tiếng Việt về chủ đề này thường đi theo lối bài giảng Java. Bài dưới đây đi vào ba phần: bốn nghĩa của từ interface, những gì đã thay đổi từ Java 8, và tiêu chí quyết định khi nào nên tạo interface. Nội dung cập nhật đến 04/11/2026.
Tóm tắt nhanh: Interface là hợp đồng hành vi. Lớp ký hợp đồng phải cài đặt đủ phương thức. Không tạo được đối tượng trực tiếp từ interface. Chỉ nên tách interface khi có từ hai lớp trở lên cùng một hành vi, hoặc khi cần thay thế và giả lập trong test.
Interface là gì?
Trong lập trình hướng đối tượng, interface là một kiểu dữ liệu chỉ chứa khai báo hành vi, không chứa phần cài đặt. Lớp muốn dùng interface phải cài đặt đầy đủ các phương thức đã khai báo. Đổi lại, mọi đoạn code nhận kiểu interface dùng được với bất kỳ lớp nào tuân thủ hợp đồng đó.

Hợp đồng nghĩa là gì trong thực tế?
Ví dụ cổng thanh toán. Một website bán hàng cần VNPay, MoMo và ZaloPay, mỗi cổng có tham số riêng và cách ký riêng. Nếu luồng đặt hàng gọi trực tiếp từng cổng, thêm cổng thứ tư là phải sửa lại luồng đó.
Interface gom phần chung thành ba hành vi: tạo thanh toán, kiểm tra trạng thái, hoàn tiền. Ba lớp cài đặt ba cổng theo ba cách khác nhau. Luồng đặt hàng chỉ biết hợp đồng, không cần biết cổng nào đang chạy phía sau.
Bốn nghĩa của từ interface
Từ khóa này xuất hiện trong bốn ngữ cảnh khác nhau, và người tìm kiếm thường gộp chung. Bảng dưới phân biệt bằng dấu hiệu nhận biết.
| Ngữ cảnh | Nghĩa | Dấu hiệu bạn đang gặp |
|---|---|---|
| OOP và ngôn ngữ lập trình | Hợp đồng hành vi giữa các lớp | Từ khóa interface, implements, abstract method |
| API và tích hợp hệ thống | Hợp đồng giữa hai hệ thống qua mạng | Endpoint, HTTP, JSON, REST, OpenAPI |
| Thiết kế sản phẩm | Giao diện người dùng nhìn thấy và bấm vào | Figma, button, layout, UI, UX |
| Phần cứng | Chuẩn kết nối giữa thiết bị và máy | USB, SATA, PCIe, driver |
Cả bốn nghĩa xoay quanh một ý chung: bề mặt tiếp giáp, nơi hai bên gặp nhau mà không cần biết phần bên trong. Nếu bạn đang học OOP, nghĩa thứ nhất là nghĩa cần nắm trước. Ba nghĩa còn lại được nói ở phần cuối bài.
Interface gồm những gì?
Đã rõ interface là gì, phần tiếp theo là những gì interface chứa. Interface không giữ dữ liệu của đối tượng. Thành phần của interface xoay quanh hành vi và hằng số, tùy ngôn ngữ mà có thêm vài loại phương thức đặc biệt.
| Thành phần | Vai trò | Ghi chú theo ngôn ngữ |
|---|---|---|
| Phương thức trừu tượng | Khai báo hành vi bắt buộc phải cài đặt | Có ở Java, C#, TypeScript, PHP, Go |
| Hằng số | Giá trị dùng chung, không đổi | Java mặc định là public static final |
| Default method | Cài đặt sẵn, lớp cài đặt được ghi đè | Java 8 trở lên, C# 8 trở lên |
| Static method | Hàm tiện ích gắn với interface | Java 8 trở lên, C# 11 trở lên |
| Private method | Hàm phụ dùng trong default method | Java 9 trở lên |
| Nested type | Kiểu phụ đi kèm hợp đồng | Java, C# |
Năm điều interface không làm được
- Không tạo đối tượng trực tiếp. Bạn không viết được new cho interface, vì interface không có constructor và không giữ trạng thái.
- Không giữ biến trạng thái. Không có biến instance cho từng đối tượng. Việc giữ trạng thái kín bên trong lớp là nhiệm vụ của đóng gói (encapsulation).
- Không đặt mức truy cập riêng cho phương thức hợp đồng. Phương thức trừu tượng luôn là public, nên mọi lớp cùng gói đều thấy. Abstract class cho phép protected khi chỉ muốn lớp con dùng.
- Không kế thừa lớp. Interface chỉ mở rộng được interface khác, không nhận được code từ một lớp.
- Không thay thế lớp dùng chung. Khi nhiều lớp cần chung logic phức tạp và trạng thái, abstract class hợp hơn.
Điều đã thay đổi từ Java 8
Câu “interface chỉ có khai báo, không có code” đúng với Java 7 và C# 7. Với ngôn ngữ hiện nay, câu này không còn đủ để phân biệt interface với abstract class.
Java 8 (2014) thêm default method và static method. Java 9 (2017) thêm private method. C# 8 (2019) thêm default interface member. C# 11 (2022) thêm static abstract member.
Nghĩa là interface đã có thể chứa code từ hơn mười năm nay. Tiêu chí phân biệt vì thế không còn là “có code hay không”, mà là “có trạng thái hay không” và “quan hệ giữa hai lớp là gì”.
Interface hoạt động như thế nào?
Interface chạy theo ba bước, đúng thứ tự này.
- Khai báo hợp đồng. Bạn viết tên interface và danh sách phương thức, không viết phần thân.
- Cài đặt hợp đồng. Lớp dùng từ khóa implements hoặc dấu hai chấm, rồi viết phần thân cho từng phương thức.
- Gọi qua kiểu interface. Code phía dùng khai báo biến theo kiểu interface, truyền vào đối tượng của lớp cụ thể.
Bước ba là chỗ interface tạo ra khác biệt thật. Biến kiểu hợp đồng trỏ được tới bất kỳ đối tượng nào cài đặt hợp đồng đó. Lúc chạy, chương trình chọn đúng phiên bản phương thức của lớp thật, không phải phiên bản của interface. Cơ chế này có tên là dispatch động.

Ví dụ chạy được
interface CongThanhToan {
ma: string
thanhToan(soTien: number): boolean
}
class Vnpay implements CongThanhToan {
ma = "vnpay"
thanhToan(soTien: number) {
return soTien !== 0
}
}
class Momo implements CongThanhToan {
ma = "momo"
thanhToan(soTien: number) {
return soTien % 1000 === 0
}
}
function xuLyDon(cong: CongThanhToan, soTien: number) {
return cong.thanhToan(soTien)
}
Hàm xuLyDon chỉ nhận kiểu CongThanhToan. Hàm không biết Vnpay hay Momo, cũng không cần biết. Thêm cổng mới chỉ là thêm một lớp cài đặt và truyền vào, không sửa hàm xử lý.
Kiểm tra kiểu xảy ra lúc nào?
Java, C# và TypeScript báo lỗi ngay lúc biên dịch nếu lớp thiếu phương thức. Go cũng kiểm tra lúc biên dịch nhưng không cần từ khóa implements, chỉ cần đủ phương thức là thỏa.
Python lỏng hơn: lỗi chỉ hiện lúc gọi, trừ khi bạn chạy công cụ kiểm tra kiểu tĩnh như mypy với Protocol hoặc ABC. Với ba ngôn ngữ đầu, lỗi hiện trước khi chương trình chạy.
Ví dụ interface trong Java, C#, TypeScript và các ngôn ngữ khác
Cú pháp khác nhau, ý niệm giống nhau. Bảng dưới so sánh sáu ngôn ngữ hay gặp trong dự án Việt Nam.
| Ngôn ngữ | Khai báo | Triển khai | Đặc điểm riêng |
|---|---|---|---|
| Java | Từ khóa interface | Từ khóa implements | Cài nhiều interface, có default method từ Java 8 |
| C# | Từ khóa interface, tên có tiền tố I | Dấu hai chấm | Có default member từ C# 8, static abstract từ C# 11 |
| TypeScript | Từ khóa interface | Từ khóa implements | Chỉ tồn tại lúc biên dịch, kiểm tra theo hình dạng |
| Go | type TenInterface interface | Không cần từ khóa | Thỏa mãn ngầm định, chuộng interface nhỏ |
| PHP | Từ khóa interface | Từ khóa implements | Cài nhiều interface, không có default method |
| Python | Protocol hoặc ABC | Kế thừa ABC, hoặc khớp cấu trúc với Protocol | Kiểu tĩnh tùy chọn, thường dùng duck typing |
Java: interface là kiểu tham chiếu chuẩn
Java khai báo bằng từ khóa interface và triển khai bằng implements. Một lớp cài đặt được nhiều interface, một interface mở rộng được nhiều interface khác.
Từ Java 8, interface có default method. Đây là cách thư viện chuẩn thêm phương thức mới mà không làm hỏng lớp cũ đã cài đặt interface đó. Cũng từ Java 8, interface có đúng một phương thức trừu tượng được gọi là functional interface, nền tảng của biểu thức lambda.
Từ Java 17, interface còn khai báo được sealed để giới hạn danh sách lớp cài đặt. Nền tảng này giải thích vì sao Java vẫn là ngôn ngữ dạy OOP phổ biến ở Việt Nam.
C#: quy ước tiền tố I
C# triển khai interface bằng dấu hai chấm và đặt tiền tố I trước tên, ví dụ IThanhToan. Quy ước này giúp đọc code nhanh hơn, nhưng không phải quy tắc của trình biên dịch.
Từ C# 8, interface có default member. Từ C# 11, interface khai báo được static abstract member, nền tảng cho generic math trong thư viện chuẩn.
TypeScript: interface biến mất sau khi build
Interface trong TypeScript chỉ tồn tại lúc biên dịch. Sau khi build, interface không còn trong JavaScript, nên không tốn bộ nhớ và không có bảng dispatch riêng.
TypeScript dùng structural typing. Một object có đủ hình dạng là thỏa interface, không cần khai báo implements. Đây là khác biệt lớn nhất so với Java, nơi quan hệ phải khai báo tường minh ngay từ đầu.
Go: thỏa mãn ngầm định
Go không có từ khóa implements. Một kiểu thỏa interface nếu có đủ phương thức, trình biên dịch tự xác nhận khi gán.
Cách làm này đẩy việc định nghĩa interface về phía nơi dùng, không phải phía cung cấp. Thư viện chuẩn Go vì thế chuộng interface một phương thức như io.Reader hay io.Writer.
Python và PHP
Python không có từ khóa interface. Hai cách thay thế là lớp trừu tượng ABC với decorator abstractmethod, hoặc Protocol trong typing để kiểm tra kiểu tĩnh theo hình dạng. Phần lớn code Python vẫn dựa vào duck typing.
PHP có interface thật, khai báo bằng từ khóa interface và triển khai bằng implements. PHP cho một lớp cài nhiều interface nhưng không có default method.
Interface và abstract class khác nhau ở đâu?
Đây là câu hỏi hay gặp trong bài kiểm tra OOP, và cũng là chỗ dễ nhầm nhất. Hai khái niệm gần nhau nhưng giải quyết hai loại quan hệ khác nhau.
| Tiêu chí | Interface | Abstract class |
|---|---|---|
| Từ khóa | interface, implements | abstract class, extends |
| Đa kế thừa | Cài được nhiều interface | Chỉ kế thừa một lớp |
| Trạng thái | Không có biến instance | Có, giữ trạng thái của đối tượng |
| Constructor | Không có | Có |
| Phương thức có thân | Có, từ Java 8 và C# 8 | Có, ngay từ đầu |
| Mức truy cập | Thường là public | Mọi mức, gồm protected |
| Quan hệ diễn tả | Làm được gì (can-do) | Là một loại (is-a) |
| Rủi ro khi thêm phương thức | Dễ phá lớp cài đặt bên ngoài | Ít phá hơn nhờ code chung |
| Hợp với | Hợp đồng giữa các bộ phận | Chia sẻ logic và trạng thái nền |

Chọn cái nào: ba tình huống
Hai lớp không cùng họ nhưng cùng hành vi. Vnpay và Momo không có lớp cha chung, chỉ cùng nhận tiền. Trường hợp này dùng interface.
Nhiều lớp cùng logic nền và cùng trạng thái. Ví dụ các loại tài khoản người dùng chia sẻ phần xác thực và hồ sơ. Trường hợp này dùng abstract class.
Cần cả hợp đồng lẫn code chung. Viết interface cho hợp đồng, viết abstract class cài đặt phần lớn interface đó, lớp cụ thể chỉ cài phần còn lại.
Một điểm dễ bỏ qua: kế thừa lớp là quan hệ chặt nhất trong OOP, sửa lớp cha là ảnh hưởng mọi lớp con. Interface lỏng hơn vì chỉ ràng buộc chữ ký, không ràng buộc phần thân.
Vì sao nên dùng interface?
Lợi ích thật của interface không nằm ở cú pháp mà ở chỗ giảm số nơi phải sửa khi hệ thống thay đổi.
1. Đa hình có kiểm soát. Cùng một lời gọi, nhiều cách thực hiện, và trình biên dịch vẫn kiểm tra được kiểu. Cách này an toàn hơn truyền chuỗi hay số nguyên đại diện cho hành vi. Chi tiết cơ chế nằm ở bài tính đa hình (polymorphism).
2. Trừu tượng hóa đúng chỗ. Người đọc code thấy hợp đồng trước, chi tiết sau. Với hệ thống lớn, thứ tự đọc này quan trọng hơn việc tiết kiệm vài dòng code. Đây là ứng dụng trực tiếp của tính trừu tượng (abstraction).
3. Giảm phụ thuộc giữa các tầng. Tầng nghiệp vụ chỉ biết hợp đồng, không biết thư viện bên dưới. Đổi thư viện gửi mail hay đổi nhà cung cấp lưu trữ không lan sang tầng nghiệp vụ. Cách làm này là nền tảng của dependency injection trong các framework hiện đại.
4. Test không cần dịch vụ thật. Lớp giả cài đặt cùng interface, trả về dữ liệu cố định. Test chạy nhanh, không phụ thuộc mạng và không tốn phí gọi API.
5. Chuẩn hóa khi nhiều người cùng làm. Hai nhóm ở hai repo vẫn ghép được nếu thống nhất hợp đồng trước. Đây là lý do các thư viện công khai đặt interface ở vị trí trung tâm.
6. Bù cho đơn kế thừa. Java và C# chỉ cho kế thừa một lớp, nên một lớp không nhận được hành vi từ hai nguồn. Interface cho phép nhận nhiều tập hành vi cùng lúc mà không vướng bài toán kim cương của kế thừa (inheritance).
Khi nào nên dùng interface, khi nào không?
Interface là công cụ, không phải nghi thức. Tạo interface cho mọi lớp là cách nhanh nhất để codebase dày lên mà không linh hoạt hơn.
Bốn dấu hiệu nên tách interface
- Có từ hai lớp trở lên cùng một nhóm hành vi.
- Cần thay cài đặt theo môi trường: bản thật, bản giả lập, bản thử nghiệm.
- Có biên giới giữa hai nhóm hoặc hai module, cần chốt hợp đồng trước khi làm song song.
- Có thư viện bên thứ ba mà bạn không muốn gọi trực tiếp ở hàng chục chỗ.
Bốn trường hợp nên khoan
- Chỉ có một lớp và chưa có dấu hiệu thứ hai. Thêm interface lúc này là thêm một tầng phải bảo trì.
- Interface chỉ có một phương thức nhưng không phải kiểu hành vi độc lập. Gộp vào interface lớn hơn thường hợp lý hơn.
- Cần chia sẻ trạng thái và logic nền. Abstract class đúng hơn.
- Đang khám phá nghiệp vụ, chưa biết biên giới ở đâu. Chờ đến khi có lớp thứ hai rồi tách.
Quy tắc chờ lần thứ hai
Viết lớp cụ thể trước, cho chạy được và có test. Khi xuất hiện nhu cầu thứ hai, tách interface lúc đó. Cách này chậm hơn vài giờ nhưng tránh được hàng chục interface rỗng nằm rải trong dự án.
Năm lỗi thường gặp khi dùng interface
Phần lớn lỗi interface không phải lỗi cú pháp. Lỗi nằm ở chỗ đặt ranh giới sai.
1. Interface quá lớn. Một interface gom mười phương thức buộc lớp cài đặt phải viết cả mười, kể cả phần không dùng. Dấu hiệu là nhiều lớp có phương thức rỗng hoặc ném ngoại lệ “chưa hỗ trợ”. Cách sửa: tách theo vai trò người dùng, mỗi interface một nhóm hành vi. Cách tách này chính là nguyên lý phân tách interface (ISP) trong SOLID.
2. Đặt tên theo lớp cài đặt. Tên kiểu IVnpayService buộc hợp đồng gắn với một nhà cung cấp. Đổi sang Momo là phải đổi tên hợp đồng ở mọi nơi. Cách sửa: đặt tên theo hành vi, ví dụ CongThanhToan.
3. Thêm phương thức vào interface đã phát hành. Mọi lớp cài đặt bên ngoài vỡ ngay khi cập nhật thư viện. Cách sửa: thêm default method, hoặc tạo interface mới mở rộng interface cũ.
4. Dùng interface thay cho lớp dữ liệu. Ở Java và C#, interface mô tả hành vi và không giữ trạng thái, nên không thay được lớp dữ liệu. Với TypeScript thì khác: interface ở đó mô tả hình dạng object nên dùng cho dữ liệu là bình thường.
5. Tạo interface chỉ để test. Nếu chỉ có một cài đặt và không có kế hoạch thay thế, lớp giả có thể tạo bằng thư viện mock mà không cần interface riêng ở mọi tầng.
Interface trong hệ thống thật: API, giao diện, phần cứng
Ba nghĩa còn lại của interface không phải cách dùng khác của cùng một từ. Cả ba đều là bề mặt tiếp giáp giữa hai bên, che phần bên trong.
API là interface giữa hai hệ thống
API đặt ra danh sách thao tác mà bên gọi được phép dùng, kèm định dạng dữ liệu và cách báo lỗi. Bên gọi không cần biết cơ sở dữ liệu hay ngôn ngữ phía sau. Bài Web API là gì đi sâu vào phần này.
Điểm giống với interface trong OOP: hai bên thống nhất hợp đồng trước, cài đặt sau, đổi cài đặt không phá bên gọi. Điểm khác: API vượt qua ranh giới mạng, nên còn phải lo phiên bản, xác thực và giới hạn tải.
Giao diện người dùng
Trong thiết kế sản phẩm, interface là phần người dùng nhìn thấy và bấm vào. Nút, form, menu, màu và khoảng cách đều thuộc UI. Phần quyết định interface có dễ dùng hay không là UX, tức cách người dùng hiểu và hoàn thành công việc.
Một sản phẩm có giao diện đẹp vẫn thất bại nếu luồng sử dụng sai. Ngược lại, giao diện đơn giản vẫn chạy tốt nếu người dùng tìm được việc cần làm.
Interface phần cứng
USB, SATA và PCIe đều là chuẩn kết nối. Thiết bị chỉ cần tuân chuẩn là cắm được vào máy, không cần biết bo mạch chủ của hãng nào.
Driver là lớp cài đặt cho hợp đồng đó. Cùng một hợp đồng, mỗi hãng viết driver riêng. Hệ điều hành gọi qua hợp đồng, không gọi trực tiếp phần cứng.
Luyện interface vào dự án thật trong bốn bước
Bài tập hiệu quả nhất không phải viết thêm interface, mà là tìm chỗ code đang lặp rồi tách hợp đồng ở đó.
- Liệt kê hành vi lặp. Đọc code, ghi ra những đoạn if hoặc switch dùng để chọn nhà cung cấp, chọn phương thức gửi, chọn loại lưu trữ.
- Viết interface nhỏ nhất. Chỉ đưa vào những phương thức mà nơi gọi thật sự cần. Ba phương thức là mức hợp lý cho lần đầu.
- Đổi điểm gọi sang kiểu interface. Giữ nguyên lớp cũ, chỉ đổi chỗ khai báo biến và tham số hàm. Chạy test sau mỗi lần đổi.
- Viết một lớp giả để kiểm chứng. Nếu lớp giả thay được lớp thật mà không sửa nơi gọi, interface đã đặt đúng chỗ.
class GiaLapThanhToan implements CongThanhToan {
ma = "gia-lap"
soLanGoi = 0
thanhToan(soTien: number) {
this.soLanGoi += 1
return soTien !== 0
}
}
const giaLap = new GiaLapThanhToan()
xuLyDon(giaLap, 50000)
console.log(giaLap.soLanGoi)
Đoạn trên chạy với Node 18 trở lên và TypeScript, hoặc dán trực tiếp vào playground TypeScript. Với Java hay C#, môi trường cần JDK hoặc .NET SDK, cài trên máy cá nhân hoặc trên một VPS Linux.
Một VPS có toàn quyền root cho phép cài đúng phiên bản JDK, Node hay .NET mà dự án cần. Môi trường này giống bản chạy thật hơn máy cá nhân, nhất là khi dự án phải chạy trên Linux.
Câu hỏi thường gặp
Interface là gì, giải thích ngắn nhất?
Interface là bản hợp đồng hành vi. Interface liệt kê những phương thức mà lớp triển khai phải có, nhưng không quy định cách làm bên trong. Lớp nào cài đặt đủ các phương thức đó thì dùng được ở mọi nơi nhận kiểu interface.
Interface và abstract class khác nhau thế nào?
Interface chỉ ràng buộc chữ ký và không giữ trạng thái, một lớp cài nhiều interface. Abstract class giữ được trạng thái, có constructor và code chung, nhưng một lớp chỉ kế thừa được một abstract class. Cần hợp đồng thì chọn interface, cần code nền thì chọn abstract class.
Có tạo được đối tượng từ interface không?
Không. Interface không có constructor và không giữ trạng thái, nên không tạo được đối tượng trực tiếp bằng từ khóa new. Muốn dùng, bạn tạo đối tượng từ lớp cài đặt rồi gán vào biến kiểu interface. Cách viết này thường được gọi là lập trình hướng hợp đồng.
Một lớp cài đặt được bao nhiêu interface?
Không giới hạn theo lý thuyết. Java, C#, TypeScript và PHP đều cho một lớp cài nhiều interface cùng lúc. Thực tế nên giữ ở mức hai đến ba interface mỗi lớp, vì nhiều hơn thường là dấu hiệu lớp đang gánh quá nhiều vai trò.
Interface có chứa code được không?
Được, với ngôn ngữ hiện đại. Java 8 thêm default method và static method, Java 9 thêm private method. C# 8 thêm default interface member. Riêng Go và PHP vẫn yêu cầu interface chỉ có chữ ký, không có phần thân phương thức.
Interface khác API ở đâu?
Interface là khái niệm trong mã nguồn, kiểm tra lúc biên dịch, chỉ tồn tại trong chương trình. API là hợp đồng qua mạng hoặc thư viện, kèm định dạng dữ liệu, xác thực và phiên bản. Cả hai là hợp đồng, nhưng một bên nằm trong code, một bên vượt ranh giới mạng.
Khi nào nên dùng interface?
Khi có từ hai lớp trở lên cùng một nhóm hành vi, khi cần thay cài đặt theo môi trường, hoặc khi cần giả lập dịch vụ trong test. Nếu chỉ có một lớp và chưa có nhu cầu thay thế, viết lớp cụ thể trước rồi tách interface sau.
Interface trong TypeScript khác Java ở đâu?
TypeScript kiểm tra theo hình dạng, nên object khớp cấu trúc là thỏa, không cần khai báo implements. Interface trong TypeScript biến mất sau khi build. Java kiểm tra theo khai báo, lớp phải ghi rõ implements, và interface vẫn tồn tại lúc chạy.
Interface có phải đa kế thừa không?
Không hoàn toàn. Đa kế thừa lớp cho phép thừa hưởng cả code và trạng thái từ nhiều lớp cha, kèm bài toán kim cương. Interface chỉ thừa hưởng chữ ký, không thừa hưởng trạng thái, nên tránh được xung đột đó.
Kết luận
Interface là gì, trả lời gọn: một hợp đồng hành vi mà lớp khác phải cài đặt, cho phép code phía dùng làm việc với nhiều lớp khác nhau qua một kiểu chung. Ba điểm đáng nhớ: interface không giữ trạng thái, không tạo được đối tượng trực tiếp, và chỉ nên tách khi có nhu cầu thứ hai.
Đừng học interface bằng cách viết thêm interface. Hãy tìm một đoạn code đang lặp if theo nhà cung cấp, tách hợp đồng ở đúng chỗ đó, rồi viết một lớp giả để kiểm chứng. Làm đúng một lần như vậy hiệu quả hơn đọc mười bài định nghĩa.



