0

OOP Bài 2: Sự khác biệt cốt lõi giữa Lập trình thủ tục (POP) và OOP.

1. Triết lý thiết kế (Cốt lõi của sự khác biệt)

  • Lập trình thủ tục (POP - Procedural Oriented Programming): Tách rời Dữ liệu và Hành động. Hệ thống được coi là một tập hợp các Hàm (Functions). Dữ liệu chạy quanh hệ thống, từ hàm này sang hàm khác giống như nguyên liệu chạy qua một dây chuyền nhà máy. Bạn tư duy theo chuỗi hành động: Bước 1 làm gì -> Bước 2 làm gì.
  • Lập trình hướng đối tượng (OOP - Object-Oriented Programming): Gắn kết Dữ liệu và Hành động. Hệ thống được coi là một tập hợp các Thực thể (Objects) giao tiếp với nhau. Dữ liệu và các hàm thao tác trên dữ liệu đó được đóng gói lại thành một khối. Bạn tư duy theo hướng phân bổ trách nhiệm: Thực thể nào chịu trách nhiệm quản lý thông tin này?

2. Bảng so sánh tổng quan

Tiêu chí Lập trình thủ tục (POP) Lập trình hướng đối tượng (OOP)
Đơn vị cấu thành Hàm (Functions / Procedures) Đối tượng (Objects)
Cách tiếp cận Top-Down (Từ trên xuống dưới) Bottom-Up (Từ dưới lên trên)
Trạng thái dữ liệu Trôi nổi tự do (Global / Passed by ref) Đóng gói an toàn (Encapsulated)
Bảo mật nội bộ Dữ liệu dễ bị thay đổi ngoài ý muốn Chỉ Object mới được phép đổi dữ liệu của chính nó
Khả năng mở rộng Rất khó, sửa một hàm có thể hỏng toàn cục Rất tốt, dễ dàng thêm Class mới mà không phá vỡ core
Ví dụ ngôn ngữ C, Pascal, Assembly, PHP thuần C++, Java, C#, PHP (OOP), Go (Struct & Interfaces)

3. Mã nguồn thực chiến: POP vs OOP

Để thấy rõ sự khác biệt, hãy lấy ví dụ về việc xử lý trừ tiền vé tàu điện (AFC system) khi hành khách đi qua cửa xoay (Turnstile).

Cách viết kiểu POP (Lập trình thủ tục)

Trong POP, dữ liệu chiếc vé chỉ là một mảng (hoặc struct) vô tri. Bất kỳ hàm nào cũng có quyền lôi nó ra và sửa đổi.

// 1. Dữ liệu nằm trơ trọi
$ticket = [
    'id' => 'TICK_999',
    'balance' => 50000,
    'status' => 'active'
];

// 2. Hàm xử lý nằm ở một nơi khác
function deductFare(&$ticketData, $amount) {
    if ($ticketData['status'] !== 'active') {
        throw new Exception("Vé không hợp lệ");
    }
    
    if ($ticketData['balance'] >= $amount) {
        $ticketData['balance'] -= $amount; // Sửa đổi dữ liệu trực tiếp
        return true;
    }
    return false;
}

// 3. Thực thi
deductFare($ticket, 15000);

Vấn đề ở đây là gì? Dữ liệu $ticket không có khả năng tự bảo vệ. Đột nhiên một lập trình viên khác trong team vô tình viết: $ticket['balance'] = -9999; ở một file khác. Hệ thống sập, dữ liệu sai bét và bạn phải lục tung hàng ngàn dòng code để tìm xem hàm nào đã làm hỏng dữ liệu này.


Cách viết kiểu OOP (Lập trình hướng đối tượng)

Trong OOP, dữ liệu số dư (balance) bị khóa kín. Cách duy nhất để trừ tiền là yêu cầu chính chiếc vé đó thực hiện việc trừ tiền.

class MetroTicket {
    private $id;
    private $balance; // Bị khóa lại, không ai can thiệp được từ bên ngoài
    private $status;

    public function __construct($id, $balance) {
        $this->id = $id;
        $this->balance = $balance;
        $this->status = 'active';
    }

    // Chiếc vé tự chịu trách nhiệm kiểm tra và trừ tiền của chính nó
    public function deductFare($amount) {
        if ($this->status !== 'active') {
            throw new Exception("Vé không hợp lệ");
        }

        if ($this->balance >= $amount) {
            $this->balance -= $amount;
            return true;
        }
        return false;
    }
    
    public function getBalance() {
        return $this->balance;
    }
}

// Thực thi
$myTicket = new MetroTicket('TICK_999', 50000);
$myTicket->deductFare(15000);

Sức mạnh của OOP ở đây: Không một đoạn code nào bên ngoài có thể làm trò $myTicket->balance = -9999 vì thuộc tính này là private. Object MetroTicket hoàn toàn làm chủ sinh mệnh và trạng thái của nó. Điều này giúp hệ thống cực kỳ bền bỉ và dễ gỡ lỗi khi mở rộng quy mô.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí