Chúng ta đang sử dụng các ngôn ngữ lập trình để giải quyết các vấn đề trong cuộc sống hàng ngày. Vì thế sẽ không lý gì chúng ta lại không thể mô hình các vấn đề này sang các ngôn ngữ lập trình hướng đối tượng. Đây chính là nơi mà lập trình hướng đối tượng (Object-oriented programming) phát huy vai trò của nó.
1. OOP là gì
OOP là viết tắt của Object-oriented programming (lập trình hướng đối tượng). OOP là một mô hình lập trình dựa trên khái niệm Object (đối tượng), mà trong đó thường chứa 2 thành phần: data và code.
- Data thường dưới dạng các fields, hay còn gọi là các attributes hoặc properties (tạm dịch chung là các thuộc tính).
- Code thường dưới dạng các procedures, hay còn gọi là methods (tạm dịch là các phương thức).
2. Các thành phần chính trong OOP
Trong OOP sẽ bao gồm 2 thành phần chính là Class và Object:
2.1 Class (lớp) trong OOP:
Class (lớp) trong OOP là các template hay cấu trúc để phục vụ cho việc xây dựng nên các Object (đối tượng). Trong đó sẽ bao gồm một tập hợp các Attribute và Methods đẻ định nghĩa các đặc tính và hành vi cho các Object.
- Attributes: định nghĩa các thông tin, đặc điểm cũng như các thuộc tính của Object.
- Methods: định nghĩa các hành vi, phương thức cũng như các hành động thường có của Object.
Ví dụ ta có Class Person với các attributes là: Họ tên, tuổi tác, nghề nghiệp và methods là: ăn, ngủ, đi làm.
2.2 Object (đối tượng) trong OOP:
Object (đối tượng) là một instance của Class, có thể hiểu là một hiện thực hay ví dụ cụ thể của một Class. Vì thế Object khi khởi tạo sẽ mang đầy đủ thông tin cụ thể mà Class đã định nghĩa.
3. 4 tính chất cơ bản trong OOP
3.1 Encapsulation (tính đóng gói)
Encapsulation là một kỹ thuật lập trình nền tảng được sử dụng để gom nhóm các attributes và methods cần thiết vào một Object. Kỹ thuật này còn được biết với tên gọi khác là Data/Information Hiding.
Data Hiding trong lập trình hướng đối tượng OOP thường dùng để bảo vệ các thành phần bên trong của Object (thường gọi là private). Các thành phần bên ngoài sẽ không được can thiệp và sử dụng các thành phần này trực tiếp mà phải thông qua các phương thức công khai (public).
3.1.1 Ví dụ cho Encapsulation
Ta có Class Account bao gồm 2 attributes cơ bản là name
và balance
. Trong thực tế đây là 2 thông tin quan trọng cần được bảo vệ, vì thế chúng sẽ là private attributes. Bên ngoài chỉ có thể sử dụng thông qua các phương thức public như:
GetName()
: trả về name của Account.GetBalance()
: trả về gía trị balance hiện có của Account.Deposite(amount)
: nạp tiền vào Account.Withdraw(amount)
: rút tiền từ Account.
Từ đó phía bên ngoài chỉ có thể sử dụng được các public methods trên. Bên ngoài cũng không cần biết các method trong Account chạy như thế nào. Tương lai nếu logic các method trên thay đổi cũng không ảnh hưởng.
3.2 Abstraction (tính trừu tượng)
Abstraction trong lập trình hướng đối tượng OOP là một kỹ thuật lập trình dùng để đơn giản hoá cấu trúc của chương trình, tập trung vào những phần quan trọng và có ý nghĩa. Những phần phức tạp sẽ được loại bỏ hay ẩn giấu đi (hiding).
3.2.1 Ví dụ cho Abstraction
Chúng ta có class UIElement đại diện cho tất cả các thành phần trong UI (User Interface - giao diện người dùng). Mỗi element có phương thức render()
để hiển thị.
Vấn đề ở đây là phương thức render được viết như thế nào trong class UIElement?! Không thể viết được!! Vì ta không biết element này là Button, hay Link, hay Image,... Vì thế render()
là một phương thức trừu tượng (abstract method). Từ đó UIElement trở thành một abstract class.
Các element cụ thể sẽ kế thừa class UIElement và viết logic hiển thị cho bản thân chúng.
3.3 Inheritance (tính kế thừa)
Inheritance trong lập trình hướng đối tượng OOP là một cơ chế xây dựng class mới dựa trên các class đã có. Các class kế thừa sẽ bao gồm toàn bộ các attributes và methods từ base class (lớp cơ sở) hay parent class (lớp cha).
Sử dụng Inheritance sẽ giúp các nhà phát triển tái sử dụng được các class đã có, giảm thiểu các duplication (sự trùng lặp) không cần thiết.
Inheritance trong OOP bao gồm 2 loại chính:
- Single Inheritance (đơn kế thừa): class chỉ có thể kế thừa từ một parent class duy nhất.
- Multiple inheritance (đa kế thừa): class có thể kế thừa từ nhiều parent class.
Đa số các ngôn ngữ lập trình hướng đối tượng OOP chỉ hỗ trợ Single Inheritance.
3.3.1 "Is-a" relationship trong Single Inheritance
"Is-a" relationship là một phương hướng để chúng ta có thể xác định khi nào nên sử dụng kế thừa trong OOP.
Ví dụ một số trường hợp cho "is-a" relationship:
- Car is a Vehicle từ đó class Car kế thừa class Vehicle.
- Cat is a Pet từ đó class Cat kế thừa class Pet.
- Button is an UIElement từ đó class Button kế thừa class UIElement.
3.3.2 "Has-a" relationship
"Has-a" relationship là một kỹ thuật nhằm thay thế cho kế thừa. Thay vì kế thừa, chúng ta sẽ phối hợp hay tổng hợp các class hiện có để tạo thành các class lớn hơn.
Trên thực tế, "Has-a" relationship giúp chúng ta vượt qua giới hạn Single Inheritance và thêm linh hoạt cho việc thiết kế các class trong OOP. Kỹ thuật này thường được biết với tên khác là Composition hoặc Aggregation.
Ví dụ một số trường hợp cho "Has-a" relationship:
- Car has an Engine từ đó class Car có attribute là class Engine.
- Order belongs to a Customer, has many Products từ đó class Order có các attribute Customer và Product.
3.4 Polymorphism (tính đa hình)
Polymorphism trong lập trình hướng đối tượng OOP cho phép một Object có thể có nhiều hình dạng và hành vi khác nhau.
Bản chất từ Polymorphism cấu tạo từ 2 chữ Hy Lạp: "poly" nghĩa là nhiều và "morph" nghĩa là hình dạng. Từ đó Polymorphism có thể tạm dịch là "đa hình".
Polymorphism trong OOP được chia làm 2 loại:
- Static Polymorphism (đa hình tĩnh): là cơ chế định nghĩa lại các methods cùng tên, nhưng có thể khác số lượng hoặc kiểu của tham số. Static Polymorphism còn được gọi là Method Overloading.
- Dynamic Polymorphism (đa hình động): là cơ chế định nghĩa lại các methods cùng tên, cùng tham số và kiểu trả về từ parent class. Dynamic Polymorphism còn được gọi là Method Overriding.
Sự khác biệt lớn nhất giữa Static và Dynamic Polymorphism là: Static Polymorphism được xử lý tại thời điểm biên dịch (compile-time). Dynamic Polymorphism được xử lý tại thời điểm chạy chương trình (runtime).
4. Vì sao nên học OOP
Có một sự thật hiển nhiên rằng dù cho chúng ta có đang sử dụng ngôn ngữ lập trình OOP hay không thì việc nắm vững OOP vẫn luôn cần thiết.
Các lý do vì sao nên học lập trình hướng đối tượng OOP:
- Tiêu chuẩn trong ngành phát triển phần mềm: OOP được phát triển và hỗ trợ từ đại đa số các ngôn ngữ lập trình, thư viện và framework phổ biến.
- Tiêu chí đầu vào bắt buộc ở các công ty phần mềm: OOP thường xuất hiện trong những yêu cầu bắt buộc trong các JD tuyển dụng developer/engineer.
- Tổ chức và thiết kế phần mềm: Các tính chất và nguyên lý của OOP thường được sử dụng trong việc thiết kế phần mềm, giảm thiểu các khai bắt trùng lặp, tăng khả năng tái sử dụng, cũng như đơn giản hoá cấu trúc phần mềm.
- Design Patterns và Design System: Các Design Patterns/System phần lớn dựa trên các nguyên lý lập trình OOP.
5. Các hạn chế của lập trình hướng đối tượng OOP
Dưới đây là một số hạn chế khi sử dụng lập trình hướng đối tượng OOP:
- Complexity: OOP có thể tăng độ phức tạp của chương trình và hệ thống, đặc biệt với người mới. Việc sử dụng thành thạo các nguyên tắc OOP cũng là một thử thách không nhỏ.
- Performance Overhead: OOP có thể gây ảnh hưởng tới hiệu năng của chương trình bởi việc gia tăng các Object và abstraction layer cũng như các dynamic polymorphism. Trong một số trường hợp cần ưu tiên hàng đầu về hiệu năng, OOP có thể trở một thành một trở ngại.
- Overdesign: Các developer ít kinh nghiệm dễ mắc phải các lỗi design phức tạp không cần thiết. Việc này dẫn dến các thiết kế phần mềm cồng kềnh, kém hiệu quả cũng như gây khó hiểu trong quá trình phát triển và maintain.
- Brittleness: Việc tái sử dụng code trong OOP đôi khi cũng gây ra các vấn đề như thay đổi code trong các base/parent class có thể dẫn tới thay đổi rất to lớn tới các class có lệ thuộc. Việc kiểm soát các thay đổi này cũng là một nỗ lực không hề nhỏ.
- Verbose Syntax: Một số ngôn ngữ hướng đối tượng OOP có thể có syntax phức tạp. Với các trường hợp cần thực thi các tác vụ rất đơn giản nhưng lại cần khai báo rất nhiều, gây trở ngại cho việc đọc hiểu và maintain.
6. Thông tin tham khảo
Việt Trần
Yêu thích tìm hiểu các công nghệ cốt lõi, kỹ thuật lập trình và thích chia sẻ chúng tới cộng đồng
follow me :
Bài viết liên quan
Remix là gì? Framework Full-Stack cho Web Developer
Oct 03, 2024 • 7 min read
Full bộ source code: Simple Task Microservices
Oct 02, 2024 • 1 min read
Microservices là gì? So sánh Microservices và Monolithic
Sep 30, 2024 • 10 min read
Fluentd là gì? So sánh Fluentd và Logstash
Sep 29, 2024 • 11 min read
Expressjs là gì? Framework phổ biến nhất cho Node.js
Sep 28, 2024 • 9 min read
Nginx là gì? Web Server đa năng cho các Hệ thống lớn
Sep 27, 2024 • 11 min read