Tính Năng Đóng Gói Encapsulation
là một trong những tính năng rất quan trọng giúp tùy chỉnh giao diện lập trình của các đối tượng code trong lập trình module
nói chung. Và đối với các ngôn ngữ OOP
không hỗ trợ Design by Contract
thì Encapsulation
còn có một ý nghĩa khác đó là góp phần giúp cho việc đảm bảo rằng dữ liệu chắc chắn sẽ được kiểm tra trước khi đặt vào các thuộc tính của object
.
Cụ thể là nếu như chúng ta có một object
biểu thị một thực thể dữ liệu mà chương trình cần quản lý thì Encapsulation
trong OOP
sẽ hướng đến việc ẩn đi các trường dữ liệu và không cho phép truy xuất hay cập nhật trực tiếp thông qua cú pháp object.property
. Như vậy hướng đi duy nhất của code sử dụng bên ngoài là tìm một phương thức methode
được object
này mở public
ra bên ngoài để gửi yêu cầu cập nhật dữ liệu, và hiển nhiên method
sẽ được gắn logic kiểm tra tính phù hợp của dữ liệu được gửi vào.
Package Privacy
Khác so với các ngôn ngữ lập trình phổ biến có hỗ trợ OOP
, tính năng đóng gói của Ada
được triển khai ở cấp các cấp độ khác nhau với điểm chung là từ khóa private
trong định nghĩa package
. Như chúng ta đã biết thì các package
trong Ada
sẽ có code định nghĩa được chia thành khu vực public
ở phía trên từ khóa private
và khu vực được ẩn đi ở phía dưới từ khóa private
.
package Person is -- public members private -- private members end Person;
Như vậy đầu tiên chúng ta sẽ có khả năng ẩn đi định nghĩa các sub-program
hỗ trợ nếu viết ở phía dưới từ khóa private
. Các thành phần này sẽ được ẩn đi với code tham chiếu từ bên ngoài package Person
nhưng lại khả dụng với các child package
. Ví dụ như package Person.Coder
mà chúng ta đã định nghĩa trong ví dụ của các bài viết trước chắc chắn sẽ có thể đọc được các kiểu dữ liệu hỗ trợ và các sub-program
mà Person
đặt trong khu vực private
.
Vì vậy nên tính năng kế thừa Inheritance
sẽ được đảm bảo hoạt động tốt nhất trong trường hợp chúng ta định nghĩa các kiểu kế thừa derived record
trong các child package
của kiểu ban đầu.
Type Encapsulation
Ở cấp độ tiếp theo, đó là khi chúng ta muốn ẩn đi các trường dữ liệu của các object
và không để code bên ngoài trực tiếp tham chiếu bằng cú pháp Object.Property
. Để sử dụng tính năng này thì Ada
chỉ cung cấp một lựa chọn tổng bộ, đó là ẩn đi toàn bộ tất cả các trường dữ liệu bằng cách di chuyển phần định nghĩa chi tiết của tagged record
vào khu vực private
. Đồng thời, tạo ra một khai báo ngắn với từ khóa private
để cho code bên ngoài có thể sử dụng tên kiểu dữ liệu để định kiểu cho các biến cần sử dụng.
package Person is type Entity is tagged private; type Class is access all Entity'Class; -- ... private type Entity is abstract tagged record Name : String (1 .. 12); end record; end Person;
Lúc này code tham chiếu từ bên ngoài sẽ biết rằng Person.Entity
là một tagged record
nhưng không biết định nghĩa chi tiết về các trường dữ liệu và chỉ có thể tương tác để gửi yêu cầu cập nhật qua sub-program
nếu được cung cấp.
Theo cảm quan cá nhân thì mình không hẳn muốn sử dụng Encapsulation
ở cấp độ này nếu như mục đích chỉ là để đảm bảo dữ liệu nạp vào object
chắc chắn sẽ được chuẩn hóa. Lý do là bởi vì Ada
có hỗ trợ các cú pháp gắn contract
để duy trì sự kiểm tra tính phù hợp của dữ liệu qua mỗi thao tác.
Đối với các sub-program
thì chúng ta có thể gắn các contract
kiểm tra dữ liệu được truyền vào các tham số và các dữ liệu trả về qua tham số out
hoặc return
với cú pháp đính kèm điều kiện Pre & Post
.
Đối với các kiểu dữ liệu thì chúng ta có thể gắn các contract
kiểm tra tính hợp lệ cả ở compile time
và run time
nhờ các yếu tố dự kiến Predicate
và Invariant
.
Thêm vào đó là khi lựa chọn sử dụng Type Encapsulation
thì chúng ta chắc chắn sẽ phải cung cấp thêm hàm khởi tạo để code sử dụng bên ngoài sử dụng bởi cú pháp new
không còn khả dụng. Có lẽ, lựa chọn tốt nhất là lựa chọn phù hợp nhất với hoàn cảnh ứng dụng và nếu như ở một thời điểm nào đó thực sự cần thiết thì chúng ta đã có Type Encapsulation
là lựa chọn backup
.