Thuộc tính tính toán
Thuộc phần Lập trình hướng đối tượng trong hành trình Lua của Coddy. Bài học 15 trên 70.
Getter và setter cho phép truy cập các giá trị đã lưu, nhưng đôi khi bạn cần dữ liệu không tồn tại dưới dạng trường đã lưu. Dữ liệu đó cần được tính toán từ các thuộc tính khác. Chúng được gọi là thuộc tính được tính toán.
Hãy xét một hình chữ nhật. Bạn lưu chiều rộng và chiều cao của nó, nhưng diện tích không được lưu ở đâu cả: diện tích được tính bằng cách nhân hai giá trị này với nhau. Thay vì lưu dữ liệu dư thừa, bạn tạo một phương thức để tính và trả về kết quả:
local Rectangle = {}
Rectangle.__index = Rectangle
function Rectangle:new(width, height)
local instance = {}
setmetatable(instance, self)
instance.width = width
instance.height = height
return instance
end
function Rectangle:getArea()
return self.width * self.height
endPhương thức :getArea() không trả về một giá trị đã lưu. Phương thức tính lại diện tích mỗi khi bạn gọi. Cách này có một ưu điểm quan trọng: nếu chiều rộng hoặc chiều cao thay đổi, diện tích sẽ tự động phản ánh kích thước mới mà bạn không cần cập nhật gì.
local box = Rectangle:new(5, 3)
print(box:getArea()) -- Đầu ra: 15
box.width = 10
print(box:getArea()) -- Đầu ra: 30Các thuộc tính được tính toán giúp đối tượng luôn nhất quán. Thay vì lưu các giá trị phụ thuộc vào những trường khác và có nguy cơ trở nên lỗi thời, bạn tính chúng khi cần. Cách này áp dụng cho mọi dữ liệu suy ra: chu vi, giá trị trung bình, chuỗi đã định dạng hoặc bất kỳ giá trị nào có thể xác định từ các thuộc tính hiện có.
Thử thách
DễHãy tạo một lớp Box để tính thể tích theo yêu cầu! Thay vì lưu thể tích dưới dạng một trường, bạn sẽ tạo một thuộc tính được tính toán từ kích thước của chiếc hộp mỗi khi cần.
Bạn sẽ sắp xếp code trong hai tệp:
Box.lua: Định nghĩa lớpBoxtheo mẫu prototype tiêu chuẩn. Mỗi chiếc hộp lưu ba kích thước:width,heightvàdepth. Bao gồm:- Hàm khởi tạo
:new(width, height, depth)để lưu cả ba kích thước - Phương thức
:getVolume()để tính và trả về thể tích (width × height × depth) - Phương thức
:getSurfaceArea()để tính và trả về tổng diện tích bề mặt
- Hàm khởi tạo
main.lua: Yêu cầu module Box, tạo một instance của chiếc hộp và minh họa cách các thuộc tính được tính toán tự động phản ánh kích thước hiện tại.
Diện tích bề mặt của một chiếc hộp được tính như sau: 2 × (width×height + height×depth + width×depth)
Bạn sẽ nhận ba đầu vào biểu thị kích thước của chiếc hộp:
- Chiều rộng
- Chiều cao
- Chiều sâu
Trong tệp chính, hãy tạo một chiếc hộp với các kích thước đã cho, sau đó in ra hai dòng:
- Thể tích bằng
:getVolume() - Diện tích bề mặt bằng
:getSurfaceArea()
Ví dụ, nếu đầu vào là 3, 4 và 5, đầu ra sẽ là:
60
94Điểm hay của các thuộc tính được tính toán là chúng luôn chính xác. Nếu sau đó bạn thay đổi một trong các kích thước của chiếc hộp, gọi lại :getVolume() sẽ tự động trả về giá trị mới chính xác, không cần cập nhật thủ công!
Tự làm thử
-- Nạp module Box
local Box = require('Box')
-- Đọc các kích thước đầu vào
local width = tonumber(io.read())
local height = tonumber(io.read())
local depth = tonumber(io.read())
-- TODO: Tạo instance hộp với các kích thước đã cho
-- TODO: In ra thể tích bằng :getVolume()
-- TODO: In ra diện tích bề mặt bằng :getSurfaceArea()
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
1Khái niệm “self”
Bảng với hàm“self” tường minhCú pháp dấu hai chấmDấu chấm và dấu hai chấmÔn tập: Điểm chuyển động4Dự án: Ngân hàng số
Thiết lập dự ánPhương thức nạp tiền2Mẫu Prototype cho lớp
Khái niệm PrototypeLiên kết bằng __indexHàm khởi tạo :new()Khởi tạo thuộc tínhCác instance độc lậpÔn tập: Nhà máy ô tô5Nạp chồng toán tử trong OOP
Cộng các đối tượngTrừ các đối tượngNối các đối tượngSo sánh các đối tượng (<, >)Ôn tập: phép tính với ví tiền8Đóng gói
Quy ước đặt tênClosure để bảo mậtTruy cập qua closureBảng chỉ đọcLogic kiểm tra hợp lệTổng kết: Két an toàn11Mẫu thiết kế (cơ bản)
Hàm tạo đối tượngBảng SingletonMẫu IteratorObserver (Listener)Ôn tập: Factory Logger3Trạng thái và hành vi của đối tượng
Biến instancePhương thức getterPhương thức setterThuộc tính tính toánĐịnh dạng chuỗiKiểm tra tính bằng nhauÔn tập: điểm số học sinh6Cơ bản về kế thừa
Thiết lập kế thừaKế thừa phương thứcMở rộng hàm khởi tạoThêm phương thức cho lớp conDùng chung và riêngÔn tập: hệ phân cấp hình dạngTự luyện tập: Trình biên dịch Lua online