Skip to content

🎯 Tại sao OOP?

OOP không phải là "cách viết code mới" — nó là cách tư duy mới về phần mềm. Thay vì hỏi "làm gì?", ta hỏi "ai làm gì?"

Vấn đề với Procedural Programming

C-style: Data và Functions tách rời

cpp
// C-style: Data riêng, functions riêng
struct BankAccount {
    int id;
    double balance;
    char ownerName[100];
};

void deposit(BankAccount* acc, double amount) {
    acc->balance += amount;  // Ai cũng có thể gọi!
}

void withdraw(BankAccount* acc, double amount) {
    acc->balance -= amount;  // Không validate!
}

int main() {
    BankAccount acc = {1, 1000.0, "Alice"};
    
    // ❌ VẤN ĐỀ 1: Ai cũng có thể truy cập trực tiếp
    acc.balance = -999999;  // Số dư âm? No protection!
    
    // ❌ VẤN ĐỀ 2: Dễ quên gọi function đúng
    acc.balance += 500;  // Bypass deposit(), không log!
    
    return 0;
}

Các vấn đề:

ProblemDescription
No encapsulationAi cũng access được data
No invariantsKhông đảm bảo rules (balance >= 0)
Scattered logicCode liên quan nằm rải rác
Hard to maintainThay đổi struct → sửa mọi nơi

OOP Solution: Gói data + behavior

cpp
#include <iostream>
#include <string>
#include <stdexcept>

class BankAccount {
private:  // 🔒 Chỉ class mới access được
    int id_;
    double balance_;
    std::string ownerName_;

public:
    // Constructor
    BankAccount(int id, const std::string& owner, double initialBalance)
        : id_(id), ownerName_(owner), balance_(initialBalance) {
        if (initialBalance < 0) {
            throw std::invalid_argument("Initial balance cannot be negative");
        }
    }

    // Getter (read-only access)
    double getBalance() const {
        return balance_;
    }

    // Deposit với validation
    void deposit(double amount) {
        if (amount <= 0) {
            throw std::invalid_argument("Deposit amount must be positive");
        }
        balance_ += amount;
        std::cout << "Deposited: " << amount << ", New balance: " << balance_ << std::endl;
    }

    // Withdraw với validation
    bool withdraw(double amount) {
        if (amount <= 0 || amount > balance_) {
            std::cout << "Withdrawal failed!" << std::endl;
            return false;
        }
        balance_ -= amount;
        std::cout << "Withdrew: " << amount << ", New balance: " << balance_ << std::endl;
        return true;
    }
};

int main() {
    BankAccount acc(1, "Alice", 1000.0);
    
    // ✅ Chỉ có thể tương tác qua methods
    acc.deposit(500);      // OK
    acc.withdraw(200);     // OK
    acc.withdraw(9999);    // FAIL — validation!
    
    // ❌ Không thể access trực tiếp
    // acc.balance_ = -999;  // Compiler error: private!
    
    std::cout << "Final balance: " << acc.getBalance() << std::endl;
    
    return 0;
}

Mapping Real World → Classes

OOP hoạt động tốt vì nó mô phỏng cách ta nghĩ về thế giới:

┌─────────────────────────────────────────────────────────────────┐
│                  REAL WORLD → C++ CLASSES                       │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  🚗 XE HƠI                       class Car {                   │
│  ─────────                       private:                       │
│  Thuộc tính:                       std::string brand_;         │
│   - Hãng                           int speed_;                  │
│   - Tốc độ                         double fuel_;                │
│   - Nhiên liệu                   public:                        │
│  Hành vi:                          void accelerate();          │
│   - Tăng tốc                       void brake();                │
│   - Phanh                          void refuel(double);         │
│   - Đổ xăng                      };                             │
│                                                                 │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  👤 NGƯỜI DÙNG                   class User {                  │
│  ─────────────                   private:                       │
│  Thuộc tính:                       std::string username_;       │
│   - Username                       std::string passwordHash_;   │
│   - Password (hashed)              int accessLevel_;            │
│   - Quyền truy cập               public:                        │
│  Hành vi:                          bool login(pwd);             │
│   - Đăng nhập                      void logout();               │
│   - Đăng xuất                      bool hasPermission(action);  │
│   - Kiểm tra quyền               };                             │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

4 Trụ cột của OOP

1. Encapsulation (Đóng gói) Học trong module này

Gói data + methods vào một đơn vị, ẩn implementation details.

cpp
class Secret {
private:
    std::string password_;  // Ẩn bên trong
public:
    bool verify(const std::string& input) {  // Chỉ expose interface
        return input == password_;
    }
};

2. Abstraction (Trừu tượng hóa) Học trong module này

Chỉ show "what" (interface), ẩn "how" (implementation).

cpp
class EmailSender {
public:
    void send(const std::string& to, const std::string& msg);
    // User không cần biết SMTP protocol bên trong!
};

3. Inheritance (Kế thừa) 🔜 Module tiếp theo

Tạo class mới dựa trên class đã có.

cpp
class Animal { ... };
class Dog : public Animal { ... };  // Dog "is-a" Animal

4. Polymorphism (Đa hình) 🔜 Module tiếp theo

Một interface, nhiều implementations.

cpp
Animal* pet = new Dog();
pet->speak();  // "Woof!" — runtime polymorphism

Khi nào KHÔNG nên dùng OOP?

OOP không phải silver bullet. Tránh over-engineering:

SituationRecommendation
Small scriptsProcedural đủ tốt
Pure data containersDùng struct (all public)
Performance-critical inner loopsData-oriented design
Simple utilitiesFree functions

📌 HPN Standard

Dùng OOP khi cần:

  • State management (objects có state phức tạp)
  • Encapsulation (bảo vệ invariants)
  • Reusability (nhiều nơi dùng cùng pattern)
  • Modeling (domain problems với entities rõ ràng)

📚 Tổng kết

ConceptKey Takeaway
ProceduralData + Functions tách rời, khó maintain
OOPData + Behavior = Object, dễ reason about
EncapsulationẨn data, chỉ expose interface
AbstractionẨn complexity, show essentials
Real-world mappingClasses phản ánh entities thực tế

➡️ Tiếp theo

Tiếp theo: Class Anatomy — Cấu trúc chi tiết của một class.