Lập trình hướng đối tượng (Object Oriented Programing) là một kĩ thuật lập trình hiện đại, đã trở thành một chuẩn lập trình chung của hầu hết các ngôn ngữ hiện nay.
Ưu điểm của OOP là có thể tái sử dụng lại code, làm đơn giản hóa độ phức tạp của bài toán và nâng cao khả năng lập trình.
Các ngôn ngữ OOP được chia thành hai dạng:
OOP thuần: đại diện là Java, nghĩa là bạn phải viết chương trình hoàn toàn bằng OOP
OOP lai: các ngôn ngữ như C++, Delphi, ... bạn có thể viết chương trình kết hợp OOP, lập trình thủ tục và hướng sự kiện.
Nói chung, các ngôn ngữ OOP lai dễ dàng và thuận tiện hơn trong việc viết mã, giúp code tự do và không bị gò bó.
Hai đối tượng cơ bản của lập trình hướng đối tượng là class và object. Hãy cùng xem qua ví dụ sau
type
TAnimal = class
procedure Sound;
end;
procedure TAnimal.Sound;
begin
Write('!!!!');
end;
begin
var Dog := TAnimal.Create;
Dog.Sound;
Dog.Free;
end;
Như trên. bạn thấy rõ ràng chia làm 3 phần:
Phần đầu: gọi là phần định nghĩa lớp với từ khóa type
Phần giữa: gọi là phần triển khai. Trong phần này, những phương thức được khai báo trong class được triển khai ra rõ ràng
Phần cuối: phần nằm trong cụm begin end. Phần này dùng để khởi tạo đối tượng (object) từ class đã có
Dễ hiểu phải không ?
Xem lại phần định nghĩa lớp TAnimal ở trên (dùng để định nghĩa một con vật). Chúng ta thấy nó vẫn còn thiếu một số thứ, giờ hãy định nghĩa thêm
type
TAnimal = class
Name: string;
procedure Sound;
function Die: boolean;
end;
Như trên, ta khai báo thêm một số thông tin cho class TAnimal. Trong đó, chúng ta thấy Name là một biến nằm trong class, gọi đó là field (trường).
Các hàm, thủ tục trong class gọi chung là phương thức (method). Ở trên, thủ tục Sound và hàm Die là các phương thức.
Các lớp được tổ chức theo hệ thống phân cấp. Lớp có thể kế thừa toàn bộ những thuộc tính, phương thức, ... từ một lớp khác. Lớp A kế thừa từ lớp B, ta gọi lớp A là lớp con (subclass), lớp B là lớp cha (parent class) hoặc lớp cơ sở (baseclass).
Ngôn ngữ Delphi sử dụng lớp TObject là lớp cơ sở cấp cao nhất, có nghĩa mọi lớp khác đều là subclass của TObject.
Lấy ví dụ về những loài động vật ở trên, ta khai báo thêm một lớp TCat là subclass của TAnimal để định nghĩa loài mèo.
type
TCat = class(TAnimal)
procedure Meooo;
end;
Cách khai báo hơi khác một chút, nhưng các bạn có thể hiểu vì sao đúng không ? Vì lớp TCat là lớp con của TAnimal, nên trong từ khóa class các bạn phải gõ TAnimal vào.
Lớp con thì có thể kế thừa, ghi đè, nạp chồng những gì đã có trong lớp cha, và cũng có thể thêm những phương thức, thuộc tính, trường mới, như trên phương thức Meooo là phương thức mới.
Quay trở lại class và object. Có thể xem class như một kiểu dữ liệu, còn object như một biến. Object là một thể hiện (instant) của class. Việc tạo ra một object từ class gọi là thực thể hóa (instantiation).
Thông thường với class, object được tạo ra nhờ phương thức Create.
var MyCat := TCat.Create;
Thực tế, ta có thể sử dụng được class thông qua object chứ không thể sử dụng trực tiếp class được. Việc sử dụng object cần gọi tên object kèm dấu chấm (.), phía sau là những phương thức hoặc trường, ... cần gọi.
MyCat.Meooo;
Write('My cat name is ', MyCat.Name);
Lưu ý lần nữa: Đoạn code sau là sai, class cần được sử dụng thông qua object, không sử dụng trực tiếp.
TCat.Meooo; // Sai
Đây là một tính chất của OOP: tính đóng gói (encapsulation). Dùng để giới hạn khả năng truy cập của class.
Ví dụ, bạn là người, bạn có thuộc tính như đoạn code sau mô tả
type
TYou = class
Name: string;
Birthday: TDateTime;
end;
Như bạn thấy, họ tên của bạn có thể chia sẻ cho ai đó, bạn bè, đồng nghiệp hoặc ai đó không quen hỏi tên. Ngược lại, ngày sinh của bạn thì bạn chỉ chia sẻ cho ai bạn thực sự quen. Đó là tính đóng gói.
Delphi sử dụng các mức truy cập (Access Modifier) để thể hiện tính đóng gói. Có 4 mức cơ bản:
Private: chỉ dùng riêng trong class
Protected: có thể dùng cho class hoặc class con của nó
Public: sử dụng công khai
Published: tương tự như public nhưng được thể hiện trong trình quản lý đối tượng Object Inspector
Tuy nhiên, các lớp trong một project có thể truy cập lẫn nhau. Để ngăn chặn điều này, bạn cần chỉ định từ khóa strict (nghiêm ngặt). Ví dụ strict private, strict protected, ...
type
TYou = class
private
Birthday: TDateTime;
public
Name: string;
end;
Các mức truy cập không cần thiết thì khỏi ghi. Với lại, các trường public thường được đặt bên ngoài các mức truy cập như thế này.
type
TYou = class
Name: string;
private
Birthday: TDateTime;
end;
Nil ám chỉ một con trỏ rỗng. Khi một object chưa khởi tạo, nó được gán là nil. Khi một string rỗng, ta có thể gán string := nil;
Hãy cẩn thận khi sử dụng một object chưa được khởi tạo, object có giá trị nil. Khi bạn truy cập vào object nil, sẽ có một ngoại lệ được ném ra, tên là Access Violate ... (quên rồi) và chương trình sẽ ngừng.
Thế nên, chúng ta cần kiểm tra một đối tượng có phải nil hay không bằng cách sử dụng if hoặc dùng hàm Assigned.
if Assigned(NewObject) = true then
...
tương đương với
if NewObject <> nil then
...
Với class, thông thường tên class luôn kèm theo chữ cái T ở đầu. Ví dụ TObject, TButton, TLabel, ...
Với object, đặt tên sao cũng được.
Với các trường, thường bao gồm chữ cái đầu là F. Ví dụ FName, FAge, ...
Thuộc tính không cần thiết, chỉ là trường bỏ đi chữ F. Ví dụ Name, Age, ...