Menu
CoddyTech

Tính đóng gói là gì?

Trong lập trình hướng đối tượng, đóng gói là giữ dữ liệu của một đối tượng và các phương thức làm việc với dữ liệu đó trong cùng một đơn vị, thường là một lớp, đồng thời giấu các chi tiết bên trong để code khác chỉ dùng được đối tượng thông qua các phương thức public của nó.

Tác giả Kevin Spektor, Co-founder & CTO

Cập nhật 24 tháng 9, 2026

Giả sử một ứng dụng ngân hàng lưu số dư của mỗi tài khoản trong một biến thường. Bất kỳ dòng nào ở bất kỳ đâu trong chương trình cũng có thể viết account.balance = -500, và không gì ngăn được nó. Khi một số dư âm xuất hiện trên môi trường production, bạn phải lục khắp codebase để tìm mọi chỗ đã động vào nó. Đóng gói (encapsulation) giải quyết chuyện này: số dư chỉ thay đổi được qua vài phương thức, và các phương thức đó áp đặt quy tắc, chẳng hạn một lần rút tiền không bao giờ được vượt quá số dư.

Đóng gói hoạt động thế nào

Đóng gói kết hợp hai ý tưởng:

  1. Gom lại. Dữ liệu (số dư) và code làm việc với nó (nạp tiền, rút tiền) nằm trong cùng một lớp.
  2. Che giấu. Code khác chỉ nhìn thấy interface public của lớp. Dữ liệu đằng sau là nội bộ, nên nó chỉ thay đổi được theo những cách lớp cho phép.

Quy tắc mà lớp bảo vệ gọi là bất biến (invariant): ở đây là "số dư không bao giờ âm". Vì mọi thay đổi đều phải đi qua các phương thức của lớp, bất biến luôn được giữ dù phần còn lại của chương trình làm gì đi nữa.

70
refused: not enough money

Code bên ngoài đọc được acct.balance, nhưng property này không có setter, nên acct.balance = 1000 sẽ ném ra AttributeError. Nếu số dư có lúc bị sai, chỉ có đúng hai phương thức cần kiểm tra.

Đóng gói trong Python

Python không có từ khóa private. Nó dựa vào những quy ước đặt tên mà lập trình viên Python nào cũng biết:

  • name: public, là một phần của interface.
  • _name: nội bộ. Không gì ngăn bạn đọc nó, nhưng dấu gạch dưới ở đầu ngầm nói "đừng phụ thuộc vào thứ này".
  • __name: Python đổi tên nó bên trong lớp (name mangling), nên lớp con không thể vô tình ghi đè lên nó.
  • @property: biến một phương thức thành thứ đọc như một thuộc tính, để sau này bạn thêm bước kiểm tra mà không phải sửa code gọi nó.
0
False
42

Name mangling ngăn sự vô tình, không ngăn việc truy cập: tên đã đổi vẫn dùng được. Python tin rằng lập trình viên sẽ tôn trọng dấu gạch dưới. Trên thực tế, phần lớn code Python dùng một dấu gạch dưới kèm @property, và để dành hai dấu gạch dưới cho những lớp được thiết kế để kế thừa. Muốn biết thêm về cách viết lớp, xem tài liệu về lớp trong Python.

Đóng gói trong Java, C++ và JavaScript

Các ngôn ngữ khác bắt buộc việc che giấu. Trong Java, một trường private chỉ dùng được bên trong chính lớp của nó:

public class BankAccount {
    private int balance;  // hidden from every other class

    public int getBalance() { return balance; }

    public void withdraw(int amount) {
        if (amount > balance) throw new IllegalArgumentException("not enough money");
        balance -= amount;
    }
}

Viết account.balance = 1000; ở một lớp khác sẽ không biên dịch được: javac báo balance has private access in BankAccount.

Ngôn ngữThành viên ẩnThành viên publicĐược thực thi bởi
Python_name, __namenameQuy ước
Javaprivate int namepublic int nameTrình biên dịch
C++Phần private:Phần public:Trình biên dịch
JavaScript#namenameEngine JavaScript

C++ mặc định thành viên của class là private và thành viên của struct là public. Các trường private # của JavaScript, được thêm vào từ ES2022, hoàn toàn không đọc được từ bên ngoài lớp. Tài liệu giải thích từng trường hợp: access modifier trong Java, access specifier trong C++ và trường private trong JavaScript.

Vì sao đóng gói quan trọng

  • Quy tắc nằm ở một chỗ. Phép kiểm tra "không rút quá số dư" được viết một lần, bên trong withdraw, thay vì trước mỗi lần rút tiền trong chương trình.
  • Bạn tự do thay đổi phần bên trong. Nếu quyết định lưu tiền dưới dạng số xu nguyên thay vì số thực, chỉ có lớp đó thay đổi. Code gọi deposit(100) vẫn chạy bình thường.
  • Gỡ lỗi dễ hơn. Khi một giá trị bị sai, nghi phạm là vài phương thức được phép thay đổi nó, chứ không phải mọi dòng trong chương trình.
  • Ít thứ phải học và kiểm thử hơn. Một lớp có ba phương thức public có thể được hiểu và kiểm thử thông qua ba phương thức đó.

Đóng gói cũng có ở cấp cao hơn lớp. Một module để lộ hai hàm và giữ mười hàm phụ trợ ở nội bộ cũng được đóng gói theo cùng cách, và một hệ điều hành chỉ cho chương trình mở tệp qua system call cũng vậy.

Nó hay bị nhầm với trừu tượng hóa. Trừu tượng hóa quyết định interface cung cấp những gì; đóng gói bảo vệ dữ liệu đằng sau interface đó. Trang trừu tượng hóa có bảng so sánh đầy đủ hai khái niệm. Cùng với đa hình và kế thừa, chúng là bốn tính chất của lập trình hướng đối tượng.

Lỗi thường gặp

  • Getter và setter cho mọi trường. Một setBalance chấp nhận mọi con số thì chẳng bảo vệ được gì. Hãy cung cấp các thao tác đối tượng cần (withdraw), không phải quyền truy cập thô vào từng trường.
  • Trả về đối tượng nội bộ. Một phương thức trả về self._items là trao cho bên gọi chính list thật, và giờ bên gọi có thể sửa nó. Hãy trả về một bản sao hoặc một tuple.
  • Coi private là bảo mật. Access modifier ngăn sai sót, không ngăn tấn công. Code Java đọc được trường private qua reflection, còn code Python đọc thẳng được _name. Mật khẩu và khóa cần được bảo vệ thật sự, như băm và mã hóa.

Học tiếp ở đâu

Đọc tiếp trừu tượng hóa, trang giải thích sự khác nhau giữa hai ý tưởng, rồi đến đa hình. Khóa học Python xây dựng lớp từng bước một, còn khóa học Java cho thấy tính đóng gói được trình biên dịch thực thi ra sao.

Câu hỏi thường gặp

Nói đơn giản, đóng gói là gì?
Đóng gói nghĩa là một đối tượng giữ dữ liệu cho riêng mình và chỉ đưa ra vài cách an toàn để dùng nó. Đối tượng tài khoản ngân hàng không cho bạn gõ thẳng số dư mới; nó cung cấp deposit và withdraw, vốn kiểm tra quy tắc trước. Tên tiếng Anh encapsulation bắt nguồn từ capsule, một lớp vỏ giữ những thứ bên trong.
Ví dụ về tính đóng gói là gì?
Lớp tài khoản ngân hàng chỉ cho phép thay đổi qua deposit và withdraw là ví dụ kinh điển. Chính list của Python là một ví dụ khác: bạn gọi append và không bao giờ phải quản lý vùng nhớ chứa các phần tử. Một module chỉ để lộ vài hàm và giữ các hàm phụ trợ ở chế độ riêng tư là đóng gói ở quy mô lớn hơn.
Ba loại đóng gói là gì?

Các bài hướng dẫn liệt kê ba loại thường muốn nói đến đóng gói biến thành viên (trường private), đóng gói hàm (phương thức phụ trợ private) và đóng gói lớp (một lớp được giấu bên trong lớp hoặc module khác). Đây không phải các phân loại chính thức; chúng là cùng một ý tưởng áp dụng cho trường, phương thức và cả lớp.

Tính đóng gói trong C++ là gì và dùng thế nào?
Trong C++, bạn đánh dấu các thành viên dữ liệu là private và cung cấp các hàm thành viên public để đọc hoặc thay đổi chúng. Thành viên của class mặc định là private, còn thành viên của struct mặc định là public. Trình biên dịch từ chối mọi đoạn code bên ngoài lớp cố dùng một thành viên private.
Đóng gói trong mạng máy tính nghĩa là gì?

Trong mạng máy tính, đóng gói nghĩa là bọc dữ liệu trong header của từng tầng giao thức trên đường đi ra: một thông điệp HTTP nằm trong một segment TCP, segment đó nằm trong một gói IP, và gói IP nằm trong một khung Ethernet. Nó trùng tên với khái niệm trong lập trình nhưng là một khái niệm khác.

Hình minh họa các ngôn ngữ lập trình của Coddy

Học lập trình cùng Coddy

Bắt đầu