Ẩn thông tin
Thuộc phần Lập trình hướng đối tượng trong hành trình C++ của Coddy. Bài học 36 trên 104.
Ẩn thông tin không chỉ đơn thuần là dùng các từ chỉ định quyền truy cập. Đây là một nguyên tắc thiết kế, trong đó bạn ẩn không chỉ dữ liệu mà còn cả chi tiết triển khai về cách lớp hoạt động bên trong.
Mục tiêu là chỉ cho người dùng lớp của bạn thấy những gì họ cần biết, đồng thời ẩn mọi thứ khác. Nhờ vậy, bạn có thể thay đổi cách triển khai nội bộ mà không ảnh hưởng đến code sử dụng lớp của bạn:
class Temperature {
double kelvin; // Cách biểu diễn nội bộ, chi tiết được ẩn đi
public:
void setCelsius(double c) {
kelvin = c + 273.15; // Phép chuyển đổi được ẩn khỏi người dùng
}
double getCelsius() const {
return kelvin - 273.15;
}
double getFahrenheit() const {
return (kelvin - 273.15) * 9.0/5.0 + 32;
}
};Người dùng lớp này không biết (và cũng không cần biết) rằng nhiệt độ được lưu trữ nội bộ theo đơn vị Kelvin. Nếu sau này bạn quyết định lưu nhiệt độ theo đơn vị Celsius, bạn chỉ cần thay đổi phần triển khai riêng tư, còn giao diện công khai vẫn giữ nguyên.
Việc tách biệt giao diện với cách triển khai mang lại nhiều lợi ích: giảm độ phức tạp cho người dùng lớp của bạn, ngăn việc sử dụng nhầm dữ liệu nội bộ và giúp bạn dễ bảo trì code hơn. Khi ẩn các chi tiết nội bộ, bạn có thể tự do tối ưu hóa hoặc tái cấu trúc mà không làm hỏng code hiện có phụ thuộc vào lớp của bạn.
Thử thách
DễHãy xây dựng một lớp Distance để minh họa tính đóng gói thông tin bằng cách lưu trữ khoảng cách nội bộ theo centimet, đồng thời cung cấp giao diện rõ ràng để làm việc với các đơn vị khác nhau. Người dùng lớp của bạn không cần biết (hoặc quan tâm) khoảng cách được lưu trữ nội bộ như thế nào: họ chỉ cần làm việc với đơn vị thuận tiện cho mình.
Bạn sẽ tạo hai tệp để sắp xếp code:
Distance.h: Định nghĩa lớpDistance, lớp này ẩn cách biểu diễn nội bộ nhưng cung cấp giao diện công khai linh hoạt. Bên trong, hãy lưu khoảng cách theo centimet (dưới dạngdouble). Đây là chi tiết triển khai được ẩn đi. Giao diện công khai cần cho phép người dùng:- Đặt khoảng cách bằng
setMeters(double m),setCentimeters(double cm)hoặcsetKilometers(double km) - Lấy khoảng cách bằng
getMeters(),getCentimeters()hoặcgetKilometers(): tất cả đều phải là phương thức const - Cộng hai khoảng cách bằng
add(const Distance& other), hàm này trả về một đối tượngDistancemới
Thêm hàm khởi tạo mặc định để khởi tạo khoảng cách bằng không. Ẩn logic chuyển đổi bên trong các phương thức: người dùng chỉ cần gọi
setKilometers(5)vàgetMeters()mà không cần bận tâm đến định dạng lưu trữ nội bộ.- Đặt khoảng cách bằng
main.cpp: Minh họa cách người dùng có thể làm việc với lớp mà không cần biết cách biểu diễn nội bộ. Đọc hai giá trị khoảng cách từ đầu vào: giá trị đầu tiên theo mét, giá trị thứ hai theo kilômét. Sau đó:- Tạo một đối tượng
Distancevà đặt giá trị bằng khoảng cách theo mét - In ra
"In meters: <value> m" - In ra
"In centimeters: <value> cm" - In ra
"In kilometers: <value> km" - Tạo đối tượng
Distancethứ hai và đặt giá trị bằng khoảng cách theo kilômét - Cộng hai khoảng cách với nhau và lưu kết quả
- In ra
"Combined in meters: <value> m"
- Tạo một đối tượng
Ưu điểm của tính đóng gói thông tin là sau này bạn có thể đổi cách lưu trữ nội bộ từ centimet sang milimet (hoặc bất kỳ đơn vị nào khác) mà không cần thay đổi cách người dùng tương tác với lớp. Giao diện công khai vẫn ổn định ngay cả khi phần triển khai thay đổi.
Định dạng tất cả giá trị đầu ra với hai chữ số thập phân bằng std::fixed và std::setprecision(2) từ <iomanip>. Chuyển chuỗi đầu vào thành số thực bằng std::stod().
Quy đổi tham khảo: 1 mét = 100 centimet, 1 kilômét = 1000 mét.
Tự làm thử
#include <iostream>
#include <string>
#include <iomanip>
#include "Distance.h"
using namespace std;
int main() {
// Đọc các giá trị đầu vào
string metersInput, kmInput;
cin >> metersInput; // Giá trị đầu tiên tính bằng mét
cin >> kmInput; // Giá trị thứ hai tính bằng kilômét
// Chuyển các chuỗi thành số thực kiểu double bằng std::stod()
double metersValue = stod(metersInput);
double kmValue = stod(kmInput);
// Định dạng đầu ra
cout << fixed << setprecision(2);
// TODO: Tạo đối tượng Distance đầu tiên và gán giá trị tính bằng mét
// TODO: In ra "In meters: <value> m"
// TODO: In ra "In centimeters: <value> cm"
// TODO: In ra "In kilometers: <value> km"
// TODO: Tạo đối tượng Distance thứ hai và gán giá trị tính bằng kilômét
// TODO: Cộng hai khoảng cách bằng phương thức add()
// TODO: In ra "Combined in meters: <value> m"
return 0;
}
Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.
Tất cả bài học trong Lập trình hướng đối tượng
1Nền tảng về OOP
Tệp bên ngoàiBiên dịch và tạo bản dựng C++Tệp header và tệp nguồnNamespace và phạm viGiới thiệu về OOP trong C++Lớp và đối tượngCon trỏ thisPhương thức (hàm thành viên)Thuộc tính (dữ liệu thành viên)Cơ bản về hàm khởi tạo và hàm hủyÔn tập: máy tính đơn giản4Thuộc tính của lớp
Thành viên đối tượng và thành viên tĩnhHàm truy xuất và hàm thiết lậpHàm thành viên hằngTừ khóa mutablePhương thức và biến tĩnhHàm và lớp bạnÔn tập: Trình quản lý tài khoản ngân hàng7Kế thừa
Kế thừa cơ bảnMức truy cập trong kế thừaThứ tự gọi hàm khởi tạo và hàm hủyGhi đè phương thứcHàm ảo và VTableĐa kế thừaKế thừa ảoÔn tập: hệ phân cấp nhân viên2Quản lý bộ nhớ
Bộ nhớ ngăn xếp và heapCon trỏ và tham chiếuBộ nhớ động (new/delete)Con trỏ thông minh trong C++RAII trong C++Ôn tập: Trình quản lý mảng động5Tính đóng gói
Phạm vi truy cập trong C++Tìm hiểu sâu về phạm vi truy cậpẨn thông tinStruct và lớpLớp lồng nhau và lớp bên trongÔn tập: hệ thống hồ sơ sinh viên8Đa hình
Đa hình lúc biên dịch và khi chạyNạp chồng hàmÔn lại hàm ảoHàm ảo thuần túyLớp trừu tượngThiết kế interface trong C++Ép kiểu động và RTTIÔn tập: Máy tính hình học3Hàm khởi tạo và hàm hủy
Hàm khởi tạo mặc địnhHàm khởi tạo có tham sốHàm khởi tạo sao chépHàm khởi tạo di chuyểnDanh sách khởi tạoHàm khởi tạo ủy quyềnTìm hiểu sâu về hàm hủyQuy tắc 3 / 5 / 0Ôn tập: lớp chuỗi6Nạp chồng toán tử
Giới thiệu về nạp chồng toán tửNạp chồng toán tử số họcNạp chồng toán tử so sánhToán tử luồngNạp chồng toán tử gánNạp chồng toán tử [] và ()Toán tử chuyển đổi kiểuÔn tập: lớp ma trận9Mẫu
Mẫu hàmMẫu lớpChuyên biệt hóa mẫuMẫu biến tham sốCơ bản về SFINAE và đặc điểm kiểuÔn tập: vùng chứa tổng quátTự luyện tập: Trình biên dịch C++ online