Thuộc tính để đóng gói
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 32 trên 70.
Thuộc tính là công cụ chính để triển khai tính đóng gói trong C#. Thay vì cho phép truy cập trực tiếp vào các trường, bạn bọc chúng bằng thuộc tính để kiểm soát cách truy cập và thay đổi dữ liệu.
Mẫu này kết hợp một trường riêng tư với một thuộc tính công khai có phần kiểm tra hợp lệ hoặc logic trong các bộ truy cập:
public class Temperature
{
private double celsius;
public double Celsius
{
get { return celsius; }
set
{
if (value < -273.15)
celsius = -273.15; // Giới hạn thấp nhất là độ không tuyệt đối
else
celsius = value;
}
}
}Giờ đây, code bên ngoài không thể đặt nhiệt độ bất khả thi. Thuộc tính đóng vai trò như người gác cổng, đảm bảo đối tượng của bạn luôn ở trạng thái hợp lệ. Đây là tính đóng gói trong thực tế: dữ liệu bên trong được bảo vệ nhưng vẫn có thể truy cập thông qua một giao diện có kiểm soát.
Bạn cũng có thể dùng thuộc tính để tính giá trị hoặc kích hoạt tác dụng phụ:
public double Fahrenheit
{
get { return celsius * 9 / 5 + 32; }
set { celsius = (value - 32) * 5 / 9; }
}Bên ngoài thấy hai thuộc tính, nhưng bên trong chỉ có một trường. Thuộc tính cho phép bạn thay đổi chi tiết triển khai mà không làm hỏng code sử dụng lớp của bạn, đây là lợi ích quan trọng của việc đóng gói đúng cách.
Thử thách
DễHãy xây dựng một hệ thống quản lý hàng tồn kho dùng thuộc tính để bảo vệ tính toàn vẹn của dữ liệu. Bạn sẽ tạo một lớp trong đó giá không bao giờ âm và số lượng luôn nằm trong giới hạn hợp lệ, qua đó cho thấy thuộc tính đóng vai trò như người gác cổng cho dữ liệu của bạn.
Bạn sẽ sắp xếp code trong hai tệp:
Product.cs: Tạo một lớpProducttrong không gian tênInventory, lớp này quản lý thông tin sản phẩm và kiểm tra tính hợp lệ thông qua các thuộc tính. Sản phẩm của bạn cần có:- Một trường riêng tư
price(số thập phân) cùng thuộc tính công khaiPrice, đảm bảo giá không bao giờ thấp hơn0. Nếu ai đó cố đặt giá âm, giá trị được lưu sẽ là0 - Một trường riêng tư
quantity(số nguyên) cùng thuộc tính công khaiQuantity, giữ giá trị trong khoảng từ0đến1000. Giá trị dưới 0 trở thành 0, giá trị trên 1000 trở thành 1000 - Một thuộc tính công khai tự động triển khai
Name(chuỗi) - Một thuộc tính chỉ đọc được tính toán
TotalValue, trả vềPrice * Quantity
- Một trường riêng tư
Program.cs: Trong tệp chính, hãy tạo mộtProductbằng các giá trị đầu vào. Sau đó, thử thay đổi giá và số lượng bằng các giá trị đầu vào bổ sung có thể không hợp lệ. In trạng thái sản phẩm sau khi tạo và sau mỗi lần thay đổi để xem các thuộc tính bảo vệ dữ liệu như thế nào.
Bạn sẽ nhận năm giá trị đầu vào:
- Tên sản phẩm
- Giá ban đầu (số thập phân)
- Số lượng ban đầu (số nguyên)
- Giá mới cần đặt (số thập phân, có thể âm)
- Số lượng mới cần đặt (số nguyên, có thể nằm ngoài phạm vi)
In đầu ra theo định dạng sau:
After creation:
{Name}: Price={Price}, Qty={Quantity}, Total={TotalValue}
After modifications:
{Name}: Price={Price}, Qty={Quantity}, Total={TotalValue}Ví dụ, nếu các giá trị đầu vào là Laptop, 999.99, 50, -100 và 1500, đầu ra sẽ là:
After creation:
Laptop: Price=999.99, Qty=50, Total=49999.50
After modifications:
Laptop: Price=0, Qty=1000, Total=0Hãy chú ý cách giá âm trở thành 0 và số lượng 1500 được giới hạn ở mức 1000. Các thuộc tính đang bảo vệ đối tượng khỏi những trạng thái không hợp lệ. Đây chính là tính đóng gói đang hoạt động!
Tự làm thử
using System;
using Inventory;
class Program
{
public static void Main(string[] args)
{
// Đọc các giá trị đầu vào
string name = Console.ReadLine();
decimal initialPrice = Convert.ToDecimal(Console.ReadLine());
int initialQuantity = Convert.ToInt32(Console.ReadLine());
decimal newPrice = Convert.ToDecimal(Console.ReadLine());
int newQuantity = Convert.ToInt32(Console.ReadLine());
// TODO: Tạo một Product bằng các giá trị ban đầu
// TODO: In ra trạng thái của sản phẩm sau khi tạo
Console.WriteLine("After creation:");
// Định dạng in ra: {Name}: Price={Price}, Qty={Quantity}, Total={TotalValue}
// TODO: Cập nhật giá và số lượng bằng các giá trị mới
// TODO: In ra trạng thái của sản phẩm sau khi cập nhật
Console.WriteLine("After modifications:");
// Định dạng in ra: {Name}: Price={Price}, Qty={Quantity}, Total={TotalValue}
}
}
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
1Các khái niệm cơ bản về lập trình hướng đối tượng
Tệp bên ngoàiKhông gian tên và chỉ thịGiới thiệu về lớp và đối tượngTừ khóa thisPhương thức và tham sốTrường và thuộc tínhHàm khởi tạoKhởi tạo đối tượngÔn tập: Máy tính đơn giản4Kế thừa
Cú pháp kế thừa cơ bản (:)Từ khóa 'base'Từ khóa virtual và overrideLớp sealedLớp cơ sở 'object'Ôn tập: hệ phân cấp nhân viên7Tính năng nâng cao
Nạp chồng toán tửBộ lập chỉ mục (this[])Ghi đè ToString()Phương thức mở rộngÔn tập: Danh sách tùy chỉnh10Các mẫu thiết kế phần 1
Giới thiệu về mẫu thiết kếSingleton an toàn với luồngMẫu FactoryMẫu Observer (sự kiện)Mẫu Strategy2Thuộc tính và thành viên tĩnh
Thuộc tính tự độngThuộc tính chỉ đọc hoặc chỉ ghiTrường và phương thức tĩnhLớp tĩnhThành viên có thân biểu thức5Đa hình và interface
Đa hình lúc biên dịch và lúc chạyInterface và lớp trừu tượngNhiều interfaceInterface tường minhUpcasting và downcastingÔn tập: bộ tính toán hình học8Các khái niệm OOP nâng cao
Ưu tiên composition hơn kế thừaGenerics (lớp và phương thức)Delegate và sự kiệnAttribute và reflectionGiao diện IDisposable và câu lệnh usingKiến thức cơ bản về dependency injection11Các mẫu thiết kế phần 2
Mẫu lệnhMẫu bộ chuyển đổiMẫu trang tríMẫu phương thức khuôn mẫuMẫu trạng tháiMẫu tổ hợpTự luyện tập: Trình biên dịch C# online