Phỏng vấn OOP: 4 tính chất, nguyên lý SOLID và ví dụ đời thường

  • author-image

    Nguyễn Đình Cường

  • blog-tag
  • blog-comment 0 comment
  • created-date 09 Nov, 2026
blog-thumbnail

Lập trình hướng đối tượng (OOP) là chủ đề gần như xuất hiện trong mọi buổi phỏng vấn, bất kể bạn dùng Java, C#, PHP hay Python. Câu hỏi thường bắt đầu từ định nghĩa, sau đó đào sâu bằng ví dụ. Hãy chuẩn bị những ví dụ đời thường để giải thích rõ ràng.

Bốn tính chất của OOP

1. Đóng gói (Encapsulation)

Gom dữ liệu và hành vi liên quan vào một đối tượng, che giấu chi tiết bên trong và chỉ lộ ra giao diện cần thiết. Ví dụ tài khoản ngân hàng không cho phép sửa trực tiếp số dư, bạn chỉ có thể gọi deposit() hoặc withdraw() và các phương thức này kiểm tra tính hợp lệ.

class BankAccount {  #balance = 0;  deposit(amount) {    if (amount <= 0) throw new Error('Số tiền không hợp lệ');    this.#balance += amount;  }  get balance() {    return this.#balance;  }}

2. Kế thừa (Inheritance)

Lớp con thừa hưởng thuộc tính và phương thức của lớp cha, giúp tái sử dụng code. Tuy nhiên nên dùng khi quan hệ thật sự là "là một" (xe hơi là một phương tiện). Nếu chỉ muốn dùng lại chức năng, hãy ưu tiên thành phần (composition) vì kế thừa sâu làm code cứng nhắc.

3. Đa hình (Polymorphism)

Cùng một lời gọi nhưng các đối tượng khác nhau phản hồi theo cách riêng.

class Animal { speak() { return '...'; } }class Dog extends Animal { speak() { return 'Gâu'; } }class Cat extends Animal { speak() { return 'Meo'; } }[new Dog(), new Cat()].forEach((a) => console.log(a.speak()));// Gâu, Meo

Đoạn code gọi speak() mà không cần biết đối tượng cụ thể là gì, nên khi thêm loài mới ta không phải sửa vòng lặp.

4. Trừu tượng (Abstraction)

Chỉ cho thấy những gì cần thiết và ẩn đi độ phức tạp. Khi bạn lái xe, bạn dùng vô lăng và bàn đạp mà không cần hiểu động cơ hoạt động ra sao. Trong code, trừu tượng thể hiện qua interface và lớp trừu tượng.

Đóng gói và trừu tượng khác nhau thế nào?

Đây là câu bẫy quen thuộc. Trừu tượng nói về thiết kế ở mức khái niệm: ta quan tâm điều gì. Đóng gói là cách hiện thực: giấu dữ liệu và cơ chế bên trong để bảo vệ trạng thái. Hai khái niệm bổ trợ nhau nhưng không giống nhau.

Nguyên lý SOLID

  • S - Single Responsibility: mỗi lớp chỉ có một lý do để thay đổi. Lớp xử lý đơn hàng không nên đồng thời gửi email và in hóa đơn.
  • O - Open/Closed: mở để mở rộng, đóng để sửa đổi. Thêm hành vi mới bằng lớp mới thay vì sửa lớp cũ.
  • L - Liskov Substitution: lớp con phải thay thế được lớp cha mà không phá hành vi mong đợi.
  • I - Interface Segregation: nhiều interface nhỏ chuyên biệt tốt hơn một interface lớn.
  • D - Dependency Inversion: phụ thuộc vào trừu tượng, không phụ thuộc vào cài đặt cụ thể.

Ví dụ ngắn về Dependency Inversion

Thay vì để OrderService tự tạo một lớp gửi email cụ thể, hãy truyền vào một đối tượng thỏa mãn interface Notifier. Khi cần đổi sang gửi tin nhắn SMS hoặc giả lập trong kiểm thử, bạn chỉ việc đổi đối tượng được truyền vào mà không sửa OrderService.

Composition over inheritance

Lời khuyên phổ biến: ưu tiên ghép các thành phần nhỏ thay vì tạo cây kế thừa sâu. Một đối tượng Car có một Engine linh hoạt hơn nhiều so với Car kế thừa từ Engine. Cách này dễ thay thế, dễ kiểm thử và ít ràng buộc hơn.

Một số câu hỏi ngắn

  • Class và object khác nhau? Class là bản thiết kế, object là thể hiện cụ thể được tạo từ class.
  • Constructor để làm gì? Khởi tạo trạng thái ban đầu của đối tượng.
  • Phương thức tĩnh là gì? Thuộc về lớp chứ không thuộc từng đối tượng.
  • Khi nào dùng interface? Khi muốn định nghĩa hợp đồng mà nhiều lớp không liên quan có thể cùng thực hiện.

Lỗi thường gặp khi trả lời về OOP

  • Chỉ đọc lại định nghĩa sách giáo khoa mà không đưa ví dụ.
  • Lẫn lộn đa hình lúc biên dịch (overload) và đa hình lúc chạy (override).
  • Cho rằng kế thừa luôn là cách tái sử dụng tốt nhất.
  • Nói về SOLID như thuộc lòng mà không áp dụng được vào code thật.

Cách khắc phục đơn giản: với mỗi nguyên lý, chuẩn bị một đoạn code "trước" và "sau" từ chính dự án của bạn, để bạn kể được vì sao refactor lại giúp code dễ bảo trì hơn.

Kết luận

Đừng chỉ đọc thuộc định nghĩa. Hãy chọn một bài toán quen thuộc như quản lý thư viện hoặc thanh toán, vẽ sơ đồ lớp và áp dụng từng nguyên lý. Khi bạn kể được thiết kế của chính mình, câu trả lời sẽ có sức nặng.

Để học OOP và thiết kế phần mềm qua dự án thực tế, bạn có thể xem các khóa tại codebem.com.

author_photo
Nguyễn Đình Cường

0 comment