Ở bài viết trước, mình đã hướng dẫn các bạn về các cú pháp cơ bản của C#, ở bài viết này hãy cùng mình đi tìm hiểu về lập trình hướng đối tượng trong ngôn ngữ này nhé.
Lập trình hướng đối tượng (OOP) - Class và Object
Khái niệm OOP
Tất cả những gì chúng ta làm từ đầu đến giờ gọi là lập trình thủ tục (viết lệnh từ trên xuống dưới theo từng bước).
Lập trình Hướng đối tượng (OOP - Object-Oriented Programming) là một cách tư duy khác. Thay vì nghĩ về các bước, chúng ta nghĩ về các thứ (đối tượng) trong thế giới thực.
Ví dụ: Khi quản lý sinh viên, chúng ta sẽ nghĩ đến đối tượng Sinh Viên, đối tượng Giáo Viên, đối tượng Lớp Học.
Class (lớp) và Object (đối tượng)
Đây là hai khái niệm cốt lõi.
● Class (Lớp): Là một bản thiết kế (blueprint). Nó định nghĩa các đặc điểm (thuộc tính) và hành vi (hàm) mà một thứ sẽ có.
Ví dụ: class SinhVien sẽ định nghĩa rằng một sinh viên phải có: Mã SV, Tên, Ngày sinh, Điểm trung bình. Và có hành vi: XepLoaiHocLuc().
● Object (Đối tượng): Là một thể hiện cụ thể được tạo ra từ bản thiết kế (Class) đó.
Ví dụ: Từ class SinhVien, ta tạo ra đối tượng sv1 ("Nguyễn Văn A") và đối tượng sv2 ("Trần Thị B"). Cả hai đều có Mã SV, Tên... nhưng giá trị của chúng khác nhau.
Cách tạo và sử dụng class
Chúng ta sẽ tạo một Class SinhVien. Trong Visual Studio, bạn có thể tạo một file mới tên SinhVien.cs (hoặc viết ngay bên dưới Class Program cho tiện).
// Đây là Class
public class SinhVien
{
// 1. Thuộc tính (Properties) - Đặc điểm, dữ liệu
// { get; set; } là cú pháp C# để cho phép đọc (get) và ghi (set) giá trị
public string MaSV { get; set; }
public string HoTen { get; set; }
public double DiemTB { get; set; }
// (Constructor và Methods sẽ ở phần sau)
}
Bây giờ, hãy quay lại file Program.cs để tạo ra các đối tượng từ class này.
// See https://aka.ms/new-console-template for more information
Console.WriteLine("Hello, World!");
// Dùng từ khóa 'new' để tạo một đối tượng (thể hiện) mới từ Class SinhVien
SinhVien sv1 = new SinhVien();
// Gán giá trị cho các thuộc tính của sv1
sv1.MaSV = "1001";
sv1.HoTen = "Nguyen Van A";
sv1.DiemTB = 8.5;
// Tạo đối tượng thứ 2
SinhVien sv2 = new SinhVien();
sv2.MaSV = "1002";
sv2.HoTen = "Tran Thi B";
sv2.DiemTB = 9.0;
// Truy cập và in dữ liệu
Console.WriteLine("Thong tin sinh vien 1:");
Console.WriteLine("Ten: " + sv1.HoTen);
Console.WriteLine("Diem: " + sv1.DiemTB);
Kết quả khi chạy chương trình:

Lập trình hướng đối tượng - Constructor và method
Bây giờ, chúng ta sẽ hoàn thiện class SinhVien
Constructor (hàm khởi tạo)
Bạn có thấy việc gán giá trị sv1.MaSV = ..., sv1.HoTen = ... hơi dài dòng không? Constructor là một phương thức đặc biệt được tự động gọi một lần duy nhất ngay khi bạn dùng từ khóa new.
Nó dùng để khởi tạo các giá trị ban đầu cho đối tượng.
Hãy sửa lại class SinhVien:
SinhVien.cs
namespace HelloWorld
{
public class SinhVien
{
// 1. Thuộc tính (Property)
public string MaSV { get; set; }
public string HoTen { get; set; }
public double DiemTB { get; set; }
// 2. Constructor (hàm khởi tạo)
// Tên của Constructor BẮT BUỘC phải trùng với tên Class
// Nó không có kiểu trả về (kể cả void)
public SinhVien(string ma, string ten, double diem)
{
// 'this' dùng để tham chiếu đến chính đối tượng hiện tại
// 'this.MaSV' là Thuộc tính của class
// 'ma' là tham số đầu vào
this.MaSV = ma;
this.HoTen = ten;
this.DiemTB = diem;
Console.WriteLine("Da tao mot sinh vien moi ten la: " + ten);
}
// Hàm sẽ được định nghĩa dưới đây
}
}
Bây giờ, cách chúng ta tạo đối tượng trong Program.cs sẽ thay đổi:
Program.cs
// See https://aka.ms/new-console-template for more information
using HelloWorld;
Console.WriteLine("Hello, World!");
// Vì Constructor yêu cầu 3 tham số (ma, ten, diem)
// nên chúng ta phải truyền vào ngay khi dùng 'new'
SinhVien sv1 = new SinhVien("1001", "Nguyen Van A", 8.5);
SinhVien sv2 = new SinhVien("1002", "Tran Thi B", 9.0);
// Dòng "Da tao mot sinh vien moi..." sẽ tự động được in ra 2 lần
Console.WriteLine("Ten sv1: " + sv1.HoTen); //In ra "Nguyen Van A"
Kết quả khi chạy chương trình:

Methods trong class
Thuộc tính (Properties) là dữ liệu. Hàm (Methods) là hành vi mà đối tượng đó có thể làm.
Một sinh viên có thể làm gì? Họ có thể XepLoaiHocLuc() dựa trên DiemTB của chính họ.
Hãy thêm phương thức này vào Class SinhVien:
SinhVien.cs
namespace HelloWorld
{
public class SinhVien
{
// 1. Thuộc tính (Property)
public string MaSV { get; set; }
public string HoTen { get; set; }
public double DiemTB { get; set; }
// 2. Constructor (hàm khởi tạo)
// Tên của Constructor BẮT BUỘC phải trùng với tên Class
// Nó không có kiểu trả về (kể cả void)
public SinhVien(string ma, string ten, double diem)
{
// 'this' dùng để tham chiếu đến đối tượng hiện tại
// 'this.MaSV' là Thuộc tính của class
// 'ma' là tham số đầu vào
this.MaSV = ma;
this.HoTen = ten;
this.DiemTB = diem;
Console.WriteLine("Da tao mot sinh vien moi ten la: " + ten);
}
// Hàm sẽ được định nghĩa dưới đây
public string XepLoaiHocLuc()
{
// 'this.DiemTB' là điểm của chính sinh viên đó
if (this.DiemTB >= 8.0)
{
return "Gioi";
}
else if (this.DiemTB >= 6.5)
{
return "Kha";
}
else if (this.DiemTB >= 5.0)
{
return "Trung Binh";
}
else
{
return "Yeu";
}
}
}
}
Sử dụng trong Program.cs
// See https://aka.ms/new-console-template for more information
using HelloWorld;
Console.WriteLine("Hello, World!");
SinhVien sv1 = new SinhVien("1001", "Nguyen Van A", 8.5);
SinhVien sv2 = new SinhVien("1002", "Tran Thi B", 6.0);
// Gọi phương thức từ chính đối tượng
string hocLucSv1 = sv1.XepLoaiHocLuc(); // hàm sẽ dùng 8.5 để tính
string hocLucSv2 = sv2.XepLoaiHocLuc(); // hàm sẽ dùng 6.0 để tính
Console.WriteLine("Hoc luc cua " + sv1.HoTen + ": " + hocLucSv1); // In ra: Gioi
Console.WriteLine("Hoc luc cua " + sv2.HoTen + ": " + hocLucSv2); // In ra: Trung Binh
Kết quả khi chạy chương trình:

Bốn tính chất cốt lõi của OOP
Lập trình hướng đối tượng có 4 tính chất cốt lõi mà bất kỳ lập trình viên nào cũng cần phải nắm vững: đóng gói, kế thừa, đa hình, trừu tượng. Hiểu và vận dụng 4 tính chất này là chìa khóa để viết code C# (cũng như các ngôn ngữ hướng đối tượng khác) một cách chuyên nghiệp, dễ bảo trì và mở rộng. Cũng vì vậy mà trong các buổi phỏng vấn, đối với những bạn ứng viên mới ra trường chưa có nhiều kinh nghiệm, các nhà tuyển dụng có thể sẽ đưa ra câu hỏi về chủ đề này để kiểm tra độ nắm vững kiến thức về OOP của các bạn.
Tính đóng gói (Encapsulation)
Đóng gói là cơ chế "che giấu" dữ liệu và các xử lý bên trong một đối tượng. Các đối tượng khác không thể truy cập trực tiếp vào dữ liệu, mà phải thông qua các phương thức (hàm) công khai (public) mà đối tượng đó cung cấp.
Tính kế thừa (Inheritance)
Kế thừa cho phép một lớp (Class con - Child Class) "thừa hưởng" lại toàn bộ thuộc tính và phương thức của một lớp khác (Class cha - Base Class).
Tính đa hình (Polymorphism)
Đa hình (Poly = nhiều, Morph = hình dạng) có nghĩa là "nhiều hình dạng". Nó cho phép một hành động (phương thức) được thực hiện theo nhiều cách khác nhau.
Điều này thường được thể hiện qua override (ghi đè), xây dựng dựa trên kế thừa.
Tính trừu tượng (Abstraction)
Trừu tượng là việc "che giấu" các chi tiết triển khai phức tạp và chỉ "phơi bày" ra các chức năng cần thiết. Nó tập trung vào "cái gì" (What) thay vì "như thế nào" (How).
Trừu tượng thường được thực hiện qua Abstract Class (Lớp trừu tượng) và Interface (Giao diện).

