Lập trình hướng đối tượng (OOP)

Lập trình hướng đối tượng (OOP) là một mẫu hình lập trình (programming paradigm) cơ bản cho nhiều ngôn ngữ lập trình, bao gồm cả Java, C++, C#,…

Chú ý: Từ paradigm có nhiều nghĩa, ở đây mượn nghĩa từ bản dịch Cấu trúc các cuộc cách mạng khoa học của tác giả Thomas Kuhn (https://ngocminhtran.com/2020/02/09/cau-truc-cac-cuoc-cach-mang-khoa-hoc/ ).

Một mẫu hình lập trình về cơ bản là một loạt các quy tắc mà bạn phải tuân theo khi viết mã, để giúp giải quyết một vấn đề cụ thể.

JavaScript là một ngôn ngữ đa mẫu hình (multi-paradigm language) và có thể được viết theo các mẫu hình lập trình khác nhau như lập trình hướng hàm (Functinal Programming), lập trình hướng thủ tục (Procedural Programming) hay lập trình hướng đối tượng (Object-Oriented Programming).

Lập trình hướng đối tượng là gì?

Lập trình hướng đối tượng (OOP) là một mẫu hình lập trình dựa trên các khái niệm về Đối tượng (Object). Điều đó có nghĩa là mọi thứ mà chúng ta đạt được bằng ngôn ngữ OOP đều thông qua các đối tượng. Ở đây, đối tượng được định nghĩa như là các thực thể trong thế giới thực như sinh viên hoặc xe hơi.

Tại sao phải viết OOP?

Mục tiêu chính của việc phát triển OOP là tổ chức cấu trúc của mã. Sử dụng OOP, mã được tổ chức mô-đun hơn và dễ bảo trì hơn. Chúng ta có thể liên kết mã với các thực thể trong thế giới thực.

Bằng cách sử dụng OOP, chúng ta đảm bảo rằng chỉ những thành viên được phép của một mã mới có thể truy cập được đến những thành viên khác. Điều đó làm cho mã của chúng ta được bảo mật hoàn toàn đối với quyền truy cập chưa được xác thực (trong mã).

Bốn cột trụ của OOP

Như đã giới thiệu trên, một mẫu hình lập trình về cơ bản là một loạt các quy tắc mà chúng ta phải tuân theo khi viết mã, để giúp giải quyết một vấn đề cụ thể. Các quy tắc hay bốn cột trụ cơ bản của lập trình hướng đối tượng là:

  • Tính đóng gói (Encapsulation)
  • Tính trừu tượng (Abstraction)
  • Tính thừa kế (Inheritance)
  • Tính đa hình (Polymorphism)

Tính đóng gói (Encapsulation)

Đóng gói được định nghĩa là liên kết dữ liệu và phương thức thành một đơn vị duy nhất để bảo vệ nó khỏi sự truy cập từ bên ngoài. Giống như một viên thuốc có chứa thuốc bên trong lớp vỏ của nó. Sử dụng các accessor như getter / setter là thực hiện quy tắc này.

Tính trừu tượng (Abstraction)

Mọi người thường hiểu nhầm tính đóng gói với tính trừu tượng. Tính trừu tượng đi trước một bước so với tính đóng gói. Trừu tượng được định nghĩa là chỉ hiển thị những thứ thiết yếu và che giấu việc thực hiện chi tiết bên trong.

Hãy lấy một ví dụ về một chiếc ô tô. Trên ô tô, chúng ta có thể thực hiện một số hành động như khởi động, ngắt và dừng. Bất cứ khi nào chúng ta thực hiện một trong những hành động này, ô tô sẽ cho một số kết quả. Những hành động này có một số hành động phụ nhất định được ẩn với chúng ta, nhưng chúng ta không cần quan tâm đến những hành động phụ đó. Đây là cách công ty xe hơi sử dụng một cách trừu tượng các chức năng để mang đến cho khách hàng của họ trải nghiệm mượt mà.

Tính thừa kế (Inheritance)

Một đối tượng / lớp A thừa kế một đối tượng / lớp B sẽ sử dụng lại các thuộc tính và phương thức từ đối tượng / lớp B. A gọi là đối tượng hay lớp con, B gọi là đối tượng / lớp cha.

Trong JavaScript, khái niệm lớp (class) xuất hiện từ ES6, trước ES6 chỉ có khái niệm đối tượng (object).

Kế thừa là một khái niệm rất quan trọng trong OOP. Ưu điểm chính của kế thừa là khả năng tái sử dụng (reusability). Khi một lớp con kế thừa từ lớp cha, chúng ta không cần phải viết lại cùng một đoạn mã. Chỉ cần thay đổi các thuộc tính từ lớp cha và tất cả các lớp con sẽ tự động kế thừa thay đổi đó. Tính kế thừa cũng cho phép đoạn mã trở nên dễ đọc hơn (readability).

Tính đa hình (Polymorphism)

Đa hình có nghĩa là ‘nhiều hơn một hình thức’. Ví dụ một kỹ sư lập trình có thể làm việc frontend, backend, DevOps và testing.

Đa hình có hai loại:

  • Đa hình thời gian biên dịch (Compile time Polymorphism): Quá tải hàm hay phương thức (method overloading) là kiểu đa hình này. Một phương thức quá tải là phương thức cùng tên nhưng khác danh sách tham số hay kiểu với phương thức có sẵn. JavaScript không hỗ trợ kiểu đa hình này.
  • Đa hình thời gian chạy (Runtime Polymorphism): Các phương thức từ lớp cha có thể được ghi đè (Method overriding) tại lớp con. Phương thức ghi đè có cùng tên, cùng kiểu, cùng danh sách tham số nhưng khác nội dung bên trong (mã thực thi).

Tính đóng gói, thừa kế và đa hình sẽ được đề cập chi tiết hơn trong khi thảo luận về lập trình hướng đối tượng trong JavaScript. Lập trình hướng đối tượng trong JS gồm hai giai đoạn:

  • Trước ES6: Trọng tâm là đối tượng (object)
  • Từ ES6: Bổ sung thêm class giúp phong cách lập trình hướng đối tượng trong JS gần gũi hơn với các ngôn ngữ lập trình hướng đối tượng khác như Java, C#, VB.