Một chương trình lớn được xây dựng từ các thư viện nhỏ hơn, mỗi thư viện đảm nhận một chức năng nhất định. Trong delphi, mỗi thư viện như vậy gọi là unit. Mỗi unit chứa trong một file .pas và được biên dịch thành file .dcu.
Unit gồm các định nghĩa hằng, kiểu dữ liệu, class, ... các hàm, thủ tục. Chương trình được phân ra nhiều unit nhỏ hơn, tương ứng với từng chức năng cụ thể.
Có một số unit có sẵn như System.SysUtils, System.Classes, ... mà bạn vẫn hay sử dụng, đó là những unit có sẵn. Trong bài này mình sẽ trình bày cách tự tạo ra một unit và sử dụng chúng trong chương trình (có thể copy sang nơi khác và sử dụng cho chương trình khác).
Một unit đầy đủ gồm 5 phần, trong đó 3 phần là bắt buộc: unit, interface và implementation.
unit TenUnit;
Khai báo tên unit
interface
Khai báo, định nghĩa uses, hằng số, kiểu dữ liệu, tên hàm, ...
implementation
Triển khai các hàm đã khai báo
initialization
Những lệnh cần thực hiện khi nạp unit
finalization
Những lệnh cần thực hiện khi đóng unit
end.
Hai phần initialization và finalization có thể bỏ qua.
Phần đầu unit bạn cần đặt tên cho unit, tên này phải trùng với tên file .pas chứa unit như trong ví dụ.
Phần này dùng để khai báo các biến, hằng số, định nghĩa, lớp, ... Dưới đây là ví dụ cho một phần interface cơ bản.
interface
uses
System.Classes;
const
MAX_VALUE: Byte = 50;
type
AClass = class
procedure Show;
end;
var
X: TStringList;
function DoNothing: boolean;
implementation
Interface nằm giữa hai từ khóa interface và implementation. Như trên, bạn có thể định nghĩa mọi thứ ở phần này.
Những hàm và thủ tục, phương thức trong class mà bạn đã khai báo ở interface phải được triển khai bên dưới implementation.
implementation
uses
VCL.Dialogs;
// Khai báo các hàm bên ngoài trước
function DoNothing: boolean;
begin
Result := true;
end;
// Sau đó mới đến các phương thức của class
procedure AClass.Show;
begin
ShowMessage('This is class');
end;
Một điểm đặc biệt là bạn có thể khai báo unit bên dưới implementation. Kĩ thuật này gọi là unit circular reference, sẽ được đề cập ở phần sau.
Phần initialization dùng để thực hiện các lệnh khi unit được nạp (khi chương trình được chạy). Phần này chủ yếu dùng để khởi tạo các biến dùng chung cho unit (trong ví dụ trên là biến X: TStringList.
initialization
X := TStringList.Create;
Phần finalization ngược lại, dùng để thực hiện các lệnh khi thoát unit. Thường dùng để xóa bỏ các đối tượng khỏi bộ nhớ.
finalization
X.Free;
Biến X được sử dụng trong toàn bộ unit, mọi hàm đều dùng chung được biến X. Không những vậy, các chương trình sử dụng unit này đều truy cập được biến X.
Biến X được dùng chung cho tất cả các đối tượng sử dụng unit.
Phần này học để biết thôi, chứ thực tế ít sử dụng.
Trong unit, có hai vị trí để khai báo thư viện sử dụng: trong interface và trong implementation.
Giả sử ta có 2 unit, Unit1 và Unit2 như sau.
unit Unit1;
interface
const VAR1 = 10;
procedure PrintVar2;
implementation
procedure PrintVar2;
begin
writeln(VAR2);
end;
end.
Unit2:
unit Unit2;
interface
const VAR2 = 15;
procedure PrintVar1;
implementation
procedure PrintVar1;
begin
writeln(VAR1);
end;
end.
Như các bạn thấy, hàm trong unit gọi đến hằng trong unit2, và hàm trong unit2 gọi đến hằng trong unit1. Như vậy, trong unit1 cần khai báo uses Unit2 và trong unit 2 cần khai báo uses Unit1.
Bạn có thể sẽ làm như sau
unit Unit1;
interface
uses Unit2;
const VAR1 = 10;
procedure PrintVar2;
implementation
procedure PrintVar2;
begin
writeln(VAR2);
end;
end.
Unit2:
unit Unit2;
interface
uses Unit1;
const VAR1 = 10;
procedure PrintVar2;
implementation
procedure PrintVar2;
begin
writeln(VAR2);
end;
end.
Nhưng đừng bao giờ thử. Khi biên dịch, Delphi sẽ bị crash. Dự án có thể bị hỏng. Lỗi này do liên kết unit vòng lặp vô tận.
Để khắc phục, chuyển dòng khai báo unit xuống dưới phần implementation. Như thế này
unit Unit1;
interface
const VAR1 = 10;
procedure PrintVar2;
implementation
uses Unit2;
procedure PrintVar2;
begin
writeln(VAR2);
end;
end.
Unit2:
unit Unit2;
interface
const VAR1 = 10;
procedure PrintVar2;
implementation
uses Unit1;
procedure PrintVar2;
begin
writeln(VAR2);
end;
end.