Classes, Objects và Abstraction: Nền Tảng của OOP

Giới thiệu
Classes và objects là các khối xây dựng cơ bản của Lập trình Hướng Đối tượng. Hiểu cách thiết kế classes, tạo objects và sử dụng abstraction hiệu quả là điều cần thiết để viết code sạch, dễ bảo trì. Trong bài viết này, chúng ta sẽ khám phá các khái niệm này một cách sâu sắc và học khi nào nên sử dụng abstract classes so với interfaces.
Những gì bạn sẽ học
✅ Hiểu sự khác biệt giữa classes và objects
✅ Làm chủ abstraction với abstract classes và interfaces
✅ Biết khi nào dùng abstract classes vs interfaces
✅ Áp dụng constructors, static members và access modifiers đúng cách
✅ Xây dựng class hierarchies được thiết kế tốt
Classes: Bản Thiết Kế
Class là một bản thiết kế (blueprint) hoặc template định nghĩa cấu trúc và hành vi của objects. Nó chỉ định:
- Dữ liệu gì object sẽ chứa (properties/attributes)
- Hành động gì object có thể thực hiện (methods/functions)
Hãy nghĩ về class như bản vẽ kiến trúc cho một ngôi nhà. Bản vẽ mô tả ngôi nhà nên được xây như thế nào, nhưng nó không phải là ngôi nhà.
Cấu trúc của một Class
TypeScript:
class Car {
// Properties (attributes) - dữ liệu
brand: string;
model: string;
year: number;
private mileage: number = 0;
// Constructor - khởi tạo
constructor(brand: string, model: string, year: number) {
this.brand = brand;
this.model = model;
this.year = year;
}
// Methods (behaviors) - hành động
drive(distance: number): void {
this.mileage += distance;
console.log(`Đang lái ${distance} km. Tổng: ${this.mileage} km`);
}
getInfo(): string {
return `${this.year} ${this.brand} ${this.model}`;
}
getMileage(): number {
return this.mileage;
}
}Python:
class Car:
def __init__(self, brand: str, model: str, year: int):
self.brand = brand
self.model = model
self.year = year
self._mileage = 0
def drive(self, distance: int) -> None:
self._mileage += distance
print(f"Đang lái {distance} km. Tổng: {self._mileage} km")
def get_info(self) -> str:
return f"{self.year} {self.brand} {self.model}"
@property
def mileage(self) -> int:
return self._mileageObjects: Instances của Classes
Object là một instance cụ thể được tạo từ một class. Nếu class là bản thiết kế, object là ngôi nhà thực sự được xây từ bản thiết kế đó.
Tạo Objects
// Tạo objects (instances) từ class Car
const myCar = new Car("Toyota", "Camry", 2023);
const yourCar = new Car("Honda", "Civic", 2022);
// Mỗi object có dữ liệu riêng
console.log(myCar.getInfo()); // "2023 Toyota Camry"
console.log(yourCar.getInfo()); // "2022 Honda Civic"
// Hành động chỉ ảnh hưởng object cụ thể đó
myCar.drive(100);
console.log(myCar.getMileage()); // 100
console.log(yourCar.getMileage()); // 0 (không bị ảnh hưởng)Class vs Object: Sự Khác Biệt Chính
| Khía cạnh | Class | Object |
|---|---|---|
| Định nghĩa | Bản thiết kế/template | Instance của class |
| Tồn tại | Tồn tại lúc compile | Tồn tại lúc runtime |
| Bộ nhớ | Không cấp phát bộ nhớ | Bộ nhớ được cấp phát cho dữ liệu |
| Tạo | Định nghĩa một lần | Tạo nhiều lần |
Constructors: Khởi Tạo Object
Constructor là method đặc biệt khởi tạo object khi nó được tạo. Nó thiết lập trạng thái ban đầu của object.
class User {
private id: string;
private email: string;
private name: string;
constructor(email: string, name: string) {
this.id = `user_${Date.now()}`;
this.email = email;
this.name = name;
}
// Static factory method - thay thế cho constructor
static createGuest(): User {
return new User("[email protected]", "Guest User");
}
static createAdmin(email: string): User {
const admin = new User(email, "Admin");
return admin;
}
}
// Sử dụng
const user1 = new User("[email protected]", "John Doe");
const guest = User.createGuest();
const admin = User.createAdmin("[email protected]");Static vs Instance Members
Instance Members
- Thuộc về mỗi object instance
- Mỗi object có bản sao riêng
- Truy cập thông qua object reference
Static Members
- Thuộc về class
- Chia sẻ giữa tất cả instances
- Truy cập thông qua tên class
class Counter {
// Static property - chia sẻ giữa tất cả instances
private static totalCount: number = 0;
// Instance property - riêng cho mỗi object
private count: number = 0;
constructor() {
Counter.totalCount++;
}
// Instance method
increment(): void {
this.count++;
}
getCount(): number {
return this.count;
}
// Static method
static getTotalCount(): number {
return Counter.totalCount;
}
}
const counter1 = new Counter();
const counter2 = new Counter();
counter1.increment();
counter1.increment();
console.log(counter1.getCount()); // 2 (riêng instance)
console.log(Counter.getTotalCount()); // 2 (chia sẻ)Abstraction: Ẩn Sự Phức Tạp
Abstraction là về việc ẩn các chi tiết implementation phức tạp và chỉ hiển thị các tính năng thiết yếu. Nó trả lời câu hỏi: "Object này làm gì?" mà không tiết lộ "Nó làm như thế nào?"
Hai Công Cụ cho Abstraction
- Abstract Classes: Implementation một phần với một số abstract methods
- Interfaces: Contract thuần túy không có implementation
Abstract Classes
Abstract class là class không thể được khởi tạo trực tiếp. Nó đóng vai trò là base cho các classes khác.
Khi nào sử dụng Abstract Classes
- Bạn muốn chia sẻ code giữa các classes liên quan chặt chẽ
- Bạn mong subclasses có common methods hoặc fields
- Bạn cần constructors hoặc non-public members
abstract class Vehicle {
protected brand: string;
protected model: string;
protected isRunning: boolean = false;
constructor(brand: string, model: string) {
this.brand = brand;
this.model = model;
}
// Concrete method - implementation chung
startEngine(): void {
if (this.isRunning) {
console.log("Động cơ đã chạy rồi");
return;
}
this.isRunning = true;
console.log(`${this.brand} ${this.model} đã khởi động`);
}
stopEngine(): void {
this.isRunning = false;
console.log(`${this.brand} ${this.model} đã dừng`);
}
// Abstract methods - phải được implement bởi subclasses
abstract calculateFuelEfficiency(): number;
abstract getVehicleType(): string;
}
class Car extends Vehicle {
private mpg: number;
constructor(brand: string, model: string, mpg: number) {
super(brand, model);
this.mpg = mpg;
}
calculateFuelEfficiency(): number {
return this.mpg;
}
getVehicleType(): string {
return "Ô tô";
}
}
class Motorcycle extends Vehicle {
private engineCC: number;
constructor(brand: string, model: string, engineCC: number) {
super(brand, model);
this.engineCC = engineCC;
}
calculateFuelEfficiency(): number {
return Math.round(50 + (1000 - this.engineCC) / 20);
}
getVehicleType(): string {
return "Xe máy";
}
}
// Sử dụng
function printVehicleInfo(vehicle: Vehicle): void {
console.log(`Loại: ${vehicle.getVehicleType()}`);
console.log(`Hiệu suất nhiên liệu: ${vehicle.calculateFuelEfficiency()} MPG`);
vehicle.startEngine();
vehicle.stopEngine();
}
const car = new Car("Toyota", "Camry", 32);
const motorcycle = new Motorcycle("Honda", "CBR", 600);
printVehicleInfo(car);
printVehicleInfo(motorcycle);Interfaces: Contract Thuần Túy
Interface định nghĩa contract mà classes phải tuân theo. Nó chỉ định methods nào class phải implement, nhưng không phải cách thực hiện.
Khi nào sử dụng Interfaces
- Bạn muốn định nghĩa capability có thể thêm vào bất kỳ class nào
- Các classes không liên quan cần implement cùng behavior
- Bạn muốn hỗ trợ multiple inheritance of type
// Interface - định nghĩa contract
interface ILogger {
log(message: string): void;
error(message: string): void;
warn(message: string): void;
}
interface IConfigurable {
configure(options: Record<string, any>): void;
}
// Class có thể implement nhiều interfaces
class ConsoleLogger implements ILogger, IConfigurable {
private prefix: string = "[LOG]";
configure(options: Record<string, any>): void {
if (options.prefix) {
this.prefix = options.prefix;
}
}
log(message: string): void {
console.log(`${this.prefix} [INFO] ${message}`);
}
error(message: string): void {
console.error(`${this.prefix} [ERROR] ${message}`);
}
warn(message: string): void {
console.warn(`${this.prefix} [WARN] ${message}`);
}
}
class FileLogger implements ILogger, IConfigurable {
private filePath: string = "/var/log/app.log";
configure(options: Record<string, any>): void {
if (options.filePath) {
this.filePath = options.filePath;
}
}
log(message: string): void {
console.log(`Ghi vào ${this.filePath}: [INFO] ${message}`);
}
error(message: string): void {
console.log(`Ghi vào ${this.filePath}: [ERROR] ${message}`);
}
warn(message: string): void {
console.log(`Ghi vào ${this.filePath}: [WARN] ${message}`);
}
}
// Sử dụng interface cho dependency injection
class UserService {
private logger: ILogger;
constructor(logger: ILogger) {
this.logger = logger;
}
createUser(email: string): void {
this.logger.log(`Đang tạo user: ${email}`);
// Logic tạo user
this.logger.log(`User đã được tạo: ${email}`);
}
}
// Dễ dàng đổi implementations
const consoleLogger = new ConsoleLogger();
const fileLogger = new FileLogger();
const devService = new UserService(consoleLogger);
const prodService = new UserService(fileLogger);Abstract Classes vs Interfaces: So Sánh
| Khía cạnh | Abstract Class | Interface |
|---|---|---|
| Implementation | Có thể có concrete methods | Không có implementation |
| State | Có thể có instance fields | Không có state |
| Constructors | Có thể có constructors | Không có constructors |
| Inheritance | Single inheritance | Multiple implementation |
| Quan hệ | Quan hệ "is-a" | Capability "can-do" |
Hướng Dẫn Quyết Định
Dùng Abstract Class khi:
- Classes chia sẻ common base với shared implementation
- Bạn cần constructors hoặc protected members
- Có clear "is-a" hierarchy
Dùng Interface khi:
- Nhiều classes không liên quan cần cùng capability
- Bạn muốn định nghĩa contract/API
- Bạn cần multiple inheritance
Access Modifiers
| Modifier | Cùng Class | Subclass | Classes Khác |
|---|---|---|---|
| public | ✅ | ✅ | ✅ |
| protected | ✅ | ✅ | ❌ |
| private | ✅ | ❌ | ❌ |
class Employee {
public name: string; // Truy cập mọi nơi
protected department: string; // Truy cập trong class và subclasses
private salary: number; // Chỉ truy cập trong class này
readonly id: string; // Không thể thay đổi sau khởi tạo
constructor(name: string, department: string, salary: number) {
this.id = `EMP_${Date.now()}`;
this.name = name;
this.department = department;
this.salary = salary;
}
}
class Manager extends Employee {
getManagerInfo(): string {
// Có thể truy cập public và protected từ parent
return `${this.name} trong phòng ${this.department}`;
// this.salary - Lỗi: private
}
}Ví Dụ Thực Tế: Hệ Thống Sản Phẩm E-commerce
// Interfaces cho capabilities
interface IPriceable {
getPrice(): number;
applyDiscount(percentage: number): void;
}
interface IShippable {
getWeight(): number;
getShippingCost(destination: string): number;
}
// Abstract base class
abstract class Product implements IPriceable, IShippable {
protected name: string;
protected basePrice: number;
protected discount: number = 0;
protected weight: number;
constructor(name: string, basePrice: number, weight: number) {
this.name = name;
this.basePrice = basePrice;
this.weight = weight;
}
getPrice(): number {
return this.basePrice * (1 - this.discount / 100);
}
applyDiscount(percentage: number): void {
this.discount = percentage;
}
getWeight(): number {
return this.weight;
}
getShippingCost(destination: string): number {
const baseRate = destination === "nội địa" ? 20000 : 100000;
return baseRate + this.weight * 5000;
}
abstract getDescription(): string;
abstract getCategory(): string;
}
// Concrete implementations
class Electronics extends Product {
private warranty: number;
private brand: string;
constructor(name: string, price: number, weight: number, brand: string, warranty: number) {
super(name, price, weight);
this.brand = brand;
this.warranty = warranty;
}
getDescription(): string {
return `${this.brand} ${this.name} - Bảo hành ${this.warranty} tháng`;
}
getCategory(): string {
return "Điện tử";
}
}
class Clothing extends Product {
private size: string;
private material: string;
constructor(name: string, price: number, weight: number, size: string, material: string) {
super(name, price, weight);
this.size = size;
this.material = material;
}
getDescription(): string {
return `${this.name} - Size ${this.size}, ${this.material}`;
}
getCategory(): string {
return "Thời trang";
}
}
// Shopping cart
class ShoppingCart {
private items: { product: Product; quantity: number }[] = [];
addItem(product: Product, quantity: number = 1): void {
this.items.push({ product, quantity });
console.log(`Đã thêm ${quantity}x ${product.getDescription()}`);
}
getTotal(): number {
return this.items.reduce(
(total, item) => total + item.product.getPrice() * item.quantity,
0
);
}
displayCart(): void {
console.log("\n=== Giỏ Hàng ===");
this.items.forEach((item) => {
console.log(`${item.quantity}x ${item.product.getDescription()}`);
console.log(` Giá: ${item.product.getPrice().toLocaleString()}đ`);
});
console.log(`\nTổng: ${this.getTotal().toLocaleString()}đ`);
}
}
// Sử dụng
const laptop = new Electronics("MacBook Pro", 45000000, 2.1, "Apple", 24);
const shirt = new Clothing("Áo Polo", 599000, 0.3, "M", "100% cotton");
laptop.applyDiscount(10);
const cart = new ShoppingCart();
cart.addItem(laptop, 1);
cart.addItem(shirt, 2);
cart.displayCart();Tổng Kết
Classes và Objects
| Khái niệm | Định nghĩa |
|---|---|
| Class | Bản thiết kế định nghĩa cấu trúc và hành vi |
| Object | Instance được tạo từ class với dữ liệu riêng |
| Constructor | Method đặc biệt khởi tạo object |
| Static | Members thuộc về class, không phải instances |
| Instance | Members thuộc về mỗi object |
Công Cụ Abstraction
| Công cụ | Sử dụng khi |
|---|---|
| Abstract Class | Chia sẻ code giữa classes liên quan, cần constructors/state |
| Interface | Định nghĩa contracts, cho phép multiple inheritance |
Best Practices
- Giữ classes tập trung: Một trách nhiệm cho mỗi class
- Dùng tên có ý nghĩa: Classes là danh từ, methods là động từ
- Ưu tiên composition: Dùng interfaces cho flexibility
- Ẩn implementation: Chỉ expose những gì cần thiết
Tiếp Theo Là Gì?
- Encapsulation và Information Hiding: Đi sâu vào bảo vệ dữ liệu
- Inheritance và Composition: Chọn cách tiếp cận đúng
- Polymorphism và Interfaces: Design patterns linh hoạt
- SOLID Principles: Thiết kế OOP sạch
Bài Tập Thực Hành
Bài Tập 1: Shape Hierarchy
Tạo abstract class Shape với concrete Circle, Rectangle, Triangle. Bao gồm:
- Abstract method
calculateArea() - Abstract method
calculatePerimeter() - Concrete method
getDescription()
Bài Tập 2: Payment System
Thiết kế hệ thống thanh toán với:
- Interface
IPaymentMethodvớipay()vàrefund() - Abstract class
BasePaymentvới common validation - Concrete classes:
CreditCard,PayPal,BankTransfer
Có câu hỏi hoặc feedback? Đừng ngại liên hệ tại [email protected] hoặc kết nối với tôi trên X.
Chúc bạn code vui vẻ! 🚀
📬 Đăng ký nhận bản tin
Nhận những bài viết mới nhất qua email mỗi tuần. Không spam, hủy đăng ký bất cứ lúc nào.
Chúng tôi tôn trọng quyền riêng tư của bạn. Hủy đăng ký bất cứ lúc nào.
💬 Comments
Đăng nhập để bình luận
Chúng tôi sẽ không đăng bất cứ điều gì mà không có sự cho phép của bạn.