Tính đóng gói có nghĩa là trạng thái của một đối tượng chỉ xảy ra thông qua một giao diện xác định, và do đó lớp có thể đảm bảo rằng trạng thái này luôn hợp lệ và phù hợp với mục đích của lớp.
Do đó, trong một số trường hợp, nó hoàn toàn phù hợp với nguyên tắc đóng gói để chỉ hiển thị một trường công khai - tất cả các giá trị có thể có cho trường đều hợp lệ với tất cả các giá trị có thể có khác của tất cả các trường khác và do đó lập trình viên có thể chủ động quyết định cho phép trường được thao tác tự do bởi mã bên ngoài.
Mặc dù vậy, những trường hợp này chủ yếu bị hạn chế đối với các lớp chủ yếu là "dữ liệu cũ thuần túy". Họ cũng không thú vị lắm về mặt này, vậy là đủ rồi.
Trong các trường hợp khác, bằng các ngôn ngữ khác, người ta sẽ có phương thức getter và setter, một thứ gì đó giống như int getId()để lấy một giá trị và void setId(int val)cập nhật nó.
Thuộc tính cho phép chúng ta sử dụng cùng một cú pháp để đọc và ghi thông qua các phương thức như chúng ta sẽ sử dụng để đọc và ghi một trường. Đây là một đường cú pháp tốt, mặc dù không quan trọng.
(Trên thực tế, do cách phản ánh hoạt động và các trường hợp chẳng hạn như DataBinder.Evalcó thể hữu ích để có một thuộc tính ngay cả khi một trường sẽ hoạt động tốt, nhưng đó là một vấn đề khác).
Cho đến khi các bộ cài đặt riêng được giới thiệu (thực tế, điều thay đổi với C # 2 là cú pháp để có bộ cài đặt riêng và bộ nhận công khai hoặc được bảo vệ trong cùng một khối), chúng ta có thể có một phương thức riêng để thực hiện công việc của bộ cài đặt riêng, vì vậy những người thiết lập riêng không thực sự cần thiết. Tuy nhiên, chúng rất tiện dụng, vì vậy mặc dù chỉ là đường cú pháp, nhưng chúng khá hữu ích.
Việc đóng gói không phải là vấn đề liệu bộ cài (hoặc bộ nhận) của bạn là công khai, riêng tư, được bảo vệ hay nội bộ mà là vấn đề liệu chúng có phù hợp hay không . Bắt đầu với mặc định của mọi trường là riêng tư (và cho vấn đề đó readonly) và sau đó khi cần thiết thêm các thành viên (cho dù thuộc tính hay phương thức) thay đổi các trường đó và đảm bảo rằng đối tượng vẫn hợp lệ khi chúng thay đổi . Điều này đảm bảo rằng bất biến của một lớp được giữ, có nghĩa là các quy tắc mô tả tập hợp các trạng thái hợp lệ mà nó có thể ở trong đó không bao giờ bị phá vỡ (các hàm tạo cũng giúp bằng cách đảm bảo rằng nó bắt đầu ở trạng thái hợp lệ như vậy).
Đối với câu hỏi cuối cùng của bạn, bất biến có nghĩa là một lớp không có bộ thiết lập công khai, được bảo vệ hoặc nội bộ và không có phương thức công khai, được bảo vệ hoặc nội bộ nào thay đổi bất kỳ trường nào. Có những mức độ này, trong C # có thể có ba độ:
Tất cả các trường cá thể của một lớp đều là readonly, do đó, ngay cả mã riêng cũng không thể thay đổi nó. Nó được đảm bảo là không thay đổi (bất cứ thứ gì cố gắng thay đổi nó sẽ không biên dịch) và có thể tối ưu hóa có thể được thực hiện ở mặt sau của điều này.
Một lớp là bất biến từ bên ngoài vì không có thành viên nào thay đổi bất kỳ điều gì, nhưng không được đảm bảo bằng cách sử dụng readonlyđể không bị thay đổi từ bên trong.
Một lớp là bất biến khi nhìn từ bên ngoài, mặc dù một số trạng thái là thay đổi như một chi tiết triển khai. Ví dụ: một trường có thể được ghi nhớ, và do đó, trong khi từ bên ngoài cố gắng lấy nó chỉ lấy cùng một giá trị, lần thử đầu tiên như vậy thực sự tính toán nó và sau đó lưu trữ nó để truy xuất trong những lần thử tiếp theo.
private File settingsFile = null;và sau đó trong một trong những nhà xây dựng:if (settingsFile == null) { settingsFile = GetSettingsFile() };. Refactoring code như vậy khiến tôi đôi khi khóc :). Chỉ vì bạn có thể đặt một thành viên trước hàm tạo, không có nghĩa là bạn phải, với nhiều hàm tạo, điều này làm cho việc tuân theo logic là CỨNG. Các bộ cài đặt riêng buộc bạn phải đặt các giá trị bên trong của hàm tạo hoặc mới hơn.