Property
Property - thuộc tính và những vấn đề liên quan
Property - thuộc tính và những vấn đề liên quan
Thuộc tính (property) về cơ bản khá giống với một trường, dùng để lưu trữ thông tin cho class. Nhưng trường chỉ là nơi lưu trữ nội dung đơn thuần, bạn chỉ có thể đặt giá trị cho trường hoặc đọc giá trị như đối với các biến. Nhưng property không chỉ đơn thuần là thế. Property cung cấp các cách thức để kiểm soát việc đọc ghi thông tin trong class, cho phép tính toán đối với các thuộc tính.
Theo nguyên lý của OOP, các field nên được để private, còn các thuộc tính thì nên đặt public. Điều này cung cấp khả năng kiểm soát truy cập cao hơn, vì các luồng dữ liệu vào ra class được property quản lý.
Property có thể được sử dụng như một field
type
TMan = class
public
property Money: Integer;
end;
Nhưng thường thấy nhất là property liên kết với một trường dữ liệu
type
TMan = class
private
FMoney: Integer;
public
property Money: Integer read FMoney write FMoney;
end;
Như trên là cú pháp khai báo property liên kết với field. Field được giữ bí mật, property thì công khai. Hai từ khóa read và write trong khai báo property mang ý nghĩa: property Money có thể đọc dữ liệu của trường FMoney (read FMoney), và cũng có thể ghi dữ liệu và FMoney (write FMoney).
Như đã biết, property có thể được liên kết với một trường, và có thể đọc và ghi vào trường đó thông qua property. Tuy nhiên, có một số thuộc tính không được phép ghi, chỉ đọc dữ liệu (read only), hoặc chỉ có thể ghi, không được đọc (write only).
Ví dụ, thuộc tính QuyDen (quỹ đen) chỉ có thể ghi vào mà không thể đọc (write only) ngoại trừ chính bản thân người đó (class đó). Còn thuộc tính Name (tên) thì chỉ có thể đọc (read only) mà không thể ghi (không thể thay đổi).
type
TMan = class
private
FName: string;
FQuyDen: Integer;
public
property Name: string read FName;
property QuyDen: Integer write FQuyDen;
end;
Như đã nói ở phần 2, thuộc tính bình thường có 2 từ khóa read và write, có nghĩa là có toàn quyền đọc và ghi. Tuy nhiên, đối với các thuộc tính chỉ đọc (read only) hoặc chỉ ghi (write only), thì một trong hai phần sẽ được bỏ đi cho phù hợp.
Getter và setter cung cấp cho property khả năng quản lý truy cập cao hơn. Với setter và getter, bạn có thể kiểm tra tính hợp lệ của thông tin đưa vào, cũng như tính đúng đắn của thông tin lấy ra.
Bên cạnh đó, bạn cũng có thể dùng getter và setter để thực hiện các phép tính toán, biến đổi thông tin cho phù hợp.
Bản chất, setter và getter là những method (nên đặt private). Property sẽ liên kết với setter, hoặc getter, hoặc cả hai, thay vì liên kết với field.
Getter thường được đặt tên là Get..., còn setter thì là Set... trong đó ... là tên trường.
A. Setter
Setter được sử dụng nhiều hơn getter, thường dùng để kiểm tra giá trị đưa vào class có chính xác và hợp lệ không. Ví dụ, ta có lớp THinhVuong như sau.
type
THinhVuong = class
private
FCanh: Integer;
public
property Canh: Integer read FCanh write FCanh;
end;
Với class trên, hãy thử suy nghĩ. Nếu thuộc tính Canh được đặt là -1, thì trường FCanh do liên kết với property Canh nên FCanh cũng mang giá trị -1. Như thế thì không đúng, cạnh hình vuông không thể là số âm.
Chúng ta sẽ sử dụng setter trong trường hợp này.
type
THinhVuong = class
private
FCanh: Integer;
procedure SetCanh(a: Integer);
public
property Canh: Integer read FCanh write SetCanh;
end;
procedure THinhVuong.SetCanh(a: Integer);
begin
if a > 0 then
FCanh := a;
end;
Setter có cấu trúc như một procedure, với một tham số có kiểu giống như property. Setter được liên kết với phần write của thuộc tính. Property khi write sẽ gọi đến SetCanh, và SetCanh sẽ thực hiện nhiệm vụ.
B. Getter
Getter thường dùng để thay đổi giá trị được lấy ra. Ví dụ như con người có thuộc tính tên FName, nhưng nếu gặp người lạ (đặt thêm thuộc tính IsNguoiLa: boolean để kiểm tra người lạ hay người quen) thì bạn có thể nói tên giả, hoặc không nói.
Đoạn code dưới đây sẽ thể hiện vấn đề trên.
type
TMan = class
private
FName: string;
function GetName: string;
public
property IsNguoiLa: boolean;
property Name: string read GetName write FName;
end;
function TMan.GetName: string;
begin
if IsNguoiLa = true then
Result := 'Bla bla' // Tên giả
else
Result := FName;
end;
Nếu setter có dạng một thủ tục, thì getter lại có dạng 1 hàm, trả về giá trị cùng kiểu với kiểu property. Getter được liên kết với phần read của property.
Giải thích code: Khi lấy giá trị của property Name, property này sẽ gọi đến phần read GetName, hàm GetName sẽ thực thi và trả về giá trị cho property Name để đưa ra ngoài.
Một property cũng có thể vừa có getter, vừa có setter.
Khá khó hiểu, khó giải thích, các bạn vui lòng xem ở link sau
http://docwiki.embarcadero.com/RADStudio/Tokyo/en/Properties_(Delphi)
Default là từ khóa đặt cho một thuộc tính cho class, dùng để truy cập trực tiếp thuộc tính đó qua tên class.
Ví dụ cơ bản là lớp TStringList (unit System.Classes).
type
TStringList = class
...
property Strings[Index: Integer]: string; read ... write ...; default;
end;
Từ khóa default đặt ở cuối property (thường là dạng mảng index), cho biết rằng, việc truy cập đến class là truy cập đến thuộc tính default.
Nhờ default, ta có thể viết mã ngắn hơn
var
S: TStringList;
...
write(S[1]);
Thay vì phải truy cập thuộc tính Strings
write(S.Strings[1]);
Khá là tiện phải không ?