CodeGym /Các khóa học /C# SELF /Áp dụng encapsulation trong thực tế

Áp dụng encapsulation trong thực tế

C# SELF
Mức độ, Bài học
Có sẵn

1. Kiểm soát truy cập

Encapsulation – không phải là “giấu hết mọi thứ”, mà là cung cấp quyền truy cập có kiểm soát.

Nhiều bạn mới học nghĩ encapsulation chỉ đơn giản là cho tất cả field thành private. Đúng là field thường private, nhưng đó chưa phải là tất cả. Ý chính không phải là giấu dữ liệu, mà là quản lý quyền truy cập tới nó.

Đôi khi điều này nghĩa là cấm hoàn toàn việc thay đổi (ví dụ, property get-only). Đôi khi – cho phép đọc và ghi nhưng có kiểm tra. Đôi khi – chỉ cho phép đọc và sửa trong class (public Type Property { get; private set; }).

Encapsulation cho phép bạn đặt ra “luật chơi” cho object của mình: xác định rõ nó có thể bị thay đổi như thế nào, và đảm bảo mọi thay đổi đều dẫn đến trạng thái hợp lệ.

Trong dự án thực tế, nhất là khi làm team lớn, nếu không có encapsulation thì sẽ loạn lắm. Ai cũng có thể sửa trực tiếp trạng thái bên trong object của người khác, dẫn đến vô số bug và xung đột. Encapsulation tạo ra trật tự và cho mỗi module (class) tự chịu trách nhiệm về dữ liệu của mình.

Đây là một trong những nền tảng của nguyên lý SOLID, đặc biệt là nguyên lý trách nhiệm đơn (Single Responsibility Principle) và nguyên lý mở/đóng (Open/Closed Principle), bạn sẽ học sau. Nhưng giờ chỉ cần nhớ: encapsulation làm code của bạn chắc chắn, linh hoạt và dễ hiểu, dễ bảo trì.


// Mục tiêu của encapsulation: hàng rào vô hình quanh dữ liệu quan trọng
// Không ai có thể vô tình "phá hỏng" từ bên ngoài!
Encapsulation bảo vệ object khỏi bị thay đổi sai

Encapsulation giống như dựng hàng rào vô hình quanh dữ liệu quan trọng của object, để không ai vô tình phá hỏng nó. Bạn đâu muốn chó của mình tự nhiên có tuổi âm – encapsulation sẽ canh chừng chuyện đó. Nó cũng giúp class dễ dùng: dev khác không cần soi vào bên trong, chỉ cần dùng những gì bạn cho phép. Và hay nhất là, nếu mai bạn muốn đổi bên trong class – ví dụ thay vì lưu tuổi là số, chuyển sang lưu ngày sinh – thì bên ngoài cũng không biết luôn, vì interface vẫn như cũ. Đó chính là giá trị thật sự của encapsulation!

2. Lợi ích của encapsulation

Tại sao nó lại quan trọng cho dự án và sự nghiệp của bạn?

Tính toàn vẹn dữ liệu (Data Integrity):
Encapsulation giúp đảm bảo dữ liệu của object luôn ở trạng thái hợp lệ, hợp lý. Điều này giảm đáng kể bug trong chương trình. Khi phỏng vấn OOP, nếu bạn giải thích được encapsulation giúp giữ data integrity thế nào, điểm cộng to luôn!

Linh hoạt & dễ bảo trì (Flexibility & Maintainability):
Giả sử ban đầu bạn lưu tuổi chó là int Age. Một năm sau khách bảo: "Giờ cần biết ngày sinh chính xác của chó!".

Không có encapsulation: Nếu Age là public int, thì hàng trăm chỗ trong code gọi trực tiếp myDog.Age. Bạn phải sửa hết, đổi int thành DateTime, và viết lại logic tính tuổi. Đau đầu luôn!

Có encapsulation: Nếu bạn có private int _age; và public int Age { get; set; }, thì chỉ cần đổi field bên trong thành private DateTime _dateOfBirth; và sửa lại logic get và set trong property Age để tính tuổi từ ngày sinh. Code bên ngoài dùng myDog.Age không hề biết gì luôn, vì nó dùng interface public Age, không đụng trực tiếp field. Đó gọi là giảm liên kết (loose coupling).

Thấy chưa, như có phép thuật ấy! Đổi “ruột” class mà “vỏ” (interface public) vẫn y nguyên!

Dễ debug hơn (Easier Debugging):
Nếu có gì sai với dữ liệu object, với encapsulation đúng thì bạn biết chắc bug nằm trong method của class đó, hoặc qua property của nó. Vùng tìm bug chỉ còn một class, không phải cả chương trình.

Thiết kế API tốt hơn:
Khi bạn encapsulate class, bạn xác định rõ cái gì là “hợp đồng” public (API), cái gì là chi tiết bên trong. Điều này giúp tạo ra interface sạch, dễ hiểu, dễ đoán cho class. API càng rõ, dev khác (hoặc chính bạn sau này) càng dễ dùng code của bạn.

Bảo mật (Security):
Dù C# không phải ngôn ngữ cho hệ thống siêu bảo mật như C++, encapsulation vẫn quan trọng. Nó giúp kiểm soát ai và cách nào được truy cập dữ liệu, ngăn thay đổi hoặc truy cập trái phép thông tin nhạy cảm nếu có trong object.

3. Encapsulation trong C# làm như thế nào?

Trong C#, encapsulation chủ yếu đạt được bằng:

Access modifier (private, public và các loại khác):
Ta cho field của class là private để không ai sửa trực tiếp từ ngoài. Đó gọi là giấu thông tin (information hiding).
Ta cho method và property là public để cung cấp quyền truy cập có kiểm soát tới data và hành vi. Đó là interface public của mình.

Property:
Như đã học, property là cú pháp ngắn cho method get (đọc) và set (ghi). Nó cho phép giấu field, nhưng vẫn cho truy cập qua “mặt tiền” public. Quan trọng nhất – trong set accessor bạn có thể thêm logic kiểm tra!

Ví dụ: Class Dog với encapsulation

Đầu tiên viết kiểu KHÔNG nên (không có encapsulation):


public class Dog
{
    public string Name;
    public int Age;

    public void Bark()
    {
        Console.WriteLine($"{Name} nói: Gâu!");
    }
}

Ở bản này, class khác có thể thoải mái sửa tên và tuổi chó. Ví dụ:

Dog dog = new Dog();
dog.Name = "";      // Có thể cho tên rỗng!
dog.Age = -100;     // Có thể cho chó "cổ đại"

Ngoài đời hiếm khi vậy. Nhưng trong code – rất hay gặp nếu không nghĩ tới encapsulation.

Bảo vệ dữ liệu: cho field private

Cho field thành private. Khi đó chỉ class mới sửa được trực tiếp:


public class Dog
{
    private string _name;
    private int _age;

    public void Bark()
    {
        Console.WriteLine($"{_name} nói: Gâu!");
    }
}

Giờ không thể truy cập kiểu này nữa:

Dog dog = new Dog();
dog._name = "Rex"; // Lỗi biên dịch!

Truy cập dữ liệu qua property (Properties)

Nhưng vẫn muốn biết tên chó (ví dụ in ra màn hình), và đôi khi – đổi tên nếu chủ mới hoặc đổi tính. Đó là lý do có property!


public class Dog
{
    private string _name;
    private int _age;

    public string Name
    {
        get { return _name; }
        set
        {
            // Thêm kiểm tra: tên không được rỗng
            if (string.IsNullOrWhiteSpace(value))
            {
                Console.WriteLine("Lỗi: tên không được rỗng!");
            }
            else
            {
                _name = value;
            }
        }
    }

    public int Age
    {
        get { return _age; }
        set
        {
            // Thực tế chút: tuổi không được âm!
            if (value < 0)
            {
                Console.WriteLine("Lỗi: tuổi không được âm!");
            }
            else
            {
                _age = value;
            }
        }
    }

    public void Bark()
    {
        Console.WriteLine($"{_name} nói: Gâu!");
    }
}

Giờ dữ liệu đã được bảo vệ, nhưng bạn vẫn làm việc qua interface kiểm soát:

Dog dog = new Dog();
dog.Name = "Barbos";      // Ok luôn!
dog.Age = 3;

dog.Name = "";            // Sẽ báo lỗi, field không đổi!
dog.Age = -1;             // Lại lỗi

Auto property

Nếu không cần logic kiểm tra, khỏi viết field riêng – dùng auto property luôn:


public class Dog
{
    public string Name { get; set; }
    public int Age { get; set; }

    public void Bark()
    {
        Console.WriteLine($"{Name} nói: Gâu!");
    }
}

Lúc này Name và Age về bản chất đã “encapsulated” – không truy cập trực tiếp được, chỉ qua property.

4. Encapsulate hành vi: chỉ cho method cần thiết ra ngoài

Encapsulation không chỉ cho data, mà còn cho method! Đôi khi method của class là “bánh răng” bên trong, không nên cho bên ngoài thấy.

Ví dụ:


public class Dog
{
    // Chỉ dùng nội bộ
    private void WagTail()
    {
        Console.WriteLine("Chó vẫy đuôi.");
    }

    // Public cho mọi người
    public void Bark()
    {
        WagTail(); // gọi method ẩn bên trong class
        Console.WriteLine("Gâu!");
    }
}

Giờ không ai ngoài chó có thể bắt nó vẫy đuôi trực tiếp:

Dog dog = new Dog();
dog.WagTail();     // Lỗi! Method private.
dog.Bark();        // Trong Bark sẽ gọi WagTail

So sánh: field, method, property và phạm vi truy cập

Tóm lại:

Thành phần class Có thể private? Có thể public? Tại sao giới hạn truy cập?
Field Có Có (nhưng đừng!) Để bảo vệ dữ liệu
Method Có Có Để giấu chi tiết thực thi
Property Có Có Kiểm soát đọc/ghi

Khuyến nghị: field nên để private, chỉ cho ra ngoài qua property hoặc method.

2
Nhiệm vụ
C# SELF, mức độ, bài học
Đã khóa
Xác thực dữ liệu trong properties
Xác thực dữ liệu trong properties
2
Nhiệm vụ
C# SELF, mức độ, bài học
Đã khóa
Đóng gói với logic trong các phương thức
Đóng gói với logic trong các phương thức
1
Khảo sát/đố vui
, cấp độ , bài học
Không có sẵn
Thuộc tính (Properties)
Thuộc tính và các modifier truy cập
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION