OOP là một thuật ngữ được sử dụng khá phổ biến thời gian gần đây. Chính vì vậy, bài viết hôm nay sẽ cập nhật thông tin chi tiết từ A-Z để bạn đọc có thể tìm hiểu chi tiết và có cái nhìn khách quan hơn về OPP!
OOP (viết tắt của Object Oriented Programming) – Lập trình hướng đối tượng là một phương pháp lập trình dựa trên khái niệm về lớp và đối tượng. OOP tập trung vào các đối tượng thao tác hơn là logic để thao tác chúng, giúp code dễ quản lý, tái sử dụng được và dễ bảo trì. Để hiểu rõ hơn về lập trình đối tượng này, bài viết sẽ lấy ví dụ khá nhiều thông qua ngôn ngữ Java nhé!
Overview
Theo Wikipedia viết:
“Lập trình hướng đối tượng (tiếng Anh: Object-oriented programming, viết tắt: OOP) là một mẫu hình lập trình dựa trên khái niệm “công nghệ đối tượng” mà trong đó, đối tượng chứa đựng các dữ liệu trên các trường thường được gọi là các thuộc tính; và mã nguồn, được tổ chức thành các phương thức…”
Khá khó hiểu đúng không, nhưng khi nghe tên “hướng đối tượng” là các bạn cũng có thể mường tượng ra kỹ thuật này sẽ xoay quanh tới 1 đối tượng (Object). Vậy lập trình hướng đối tượng là gì:
“Lập trình hướng đối tượng ( Object – Oriented Programming) là một kỹ thuật mô hình hóa một hệ thống giống với thế giới thực trong phần mềm dựa trên các đối tượng.”
Ví dụ:
Ta có một đối tượng (Object) là một con chó. Vậy theo các bạn con chó này sẽ có những đặc điểm và hành vi gì?
Đặc điểm: tên, màu lông, giống loài, xuất xứ…
Hành vi: ăn, chơi, sủa…
Vậy ta sẽ áp dụng vào code như nào
Ví dụ trên đã tái hiện lại một đối tượng có thực trong thực tế vào trong lập trình. Chính vì thế người ta nói lập trình hướng đối tượng là một mô hình hóa hệ thống các đối tượng có thực vào trong phần mềm.
Object và Class
Như đã nói phía trên, Object là những thực thể có thực trong hiện tại, vậy sẽ ra sao khi chúng ta phải tạo 38 đối tượng chỉ để thể hiện từng bạn học sinh trong một lớp? Với số lượng đối tượng lớn như vậy chúng ta nhắc tới một khái niệm đó là Class.
Class là một tập hợp các đối tượng có cùng chung những đặc điểm giống nhau.
Ta có thể hiểu đơn giản, Class như một bản thiết kế nguyên thủy, nó bao gồm tất cả những thông tin cơ bản nhất mà một đối tượng phải có. Để khi nhìn vào một Class ta có thể hình dung được ngay bản thiết kế này sẽ cho ra một sản phẩm và sản phẩm được sinh ra từ bản thiết kế này được gọi là 1 Object.
Vậy ở đây ta có thể rút ra được 2 khái niệm cơ bản:
- Class: giống như một bản thiết kế dùng để tạo ra các Object (đối tượng), bản thân Class không phải là một Object.
- Object: được tạo ra từ một Class, các object được tạo ra từ Class nào sẽ có đầy đủ các thuộc tính của Class đó.
Bốn tính chất cơ bản của OOP
Trong lập trình hướng đối tượng sẽ được chia thành 4 tính chất như sau:
- Tính kế thừa: Inheritance
- Tính đóng gói: Encapsulation
- Tính trừu tượng: Abstraction
- Tính đa hình: Polymorphism
Vậy chúng ta sẽ đi tìm hiểu về tính chất đầu tiên:
- Tâm pháp tầng thứ nhất : Inheritance
Tính kế thừa là chỉ việc một class có thể sử dụng lại những đặc điểm và tính chất của một class khác. Mục đích của tính chất này là giúp chúng ta dễ dàng mở rộng và tránh lặp code.
Để dễ hiểu hơn ta có thể xem ví dụ ở dưới:
Ở đây là ví dụ vềmột class có tên là Person với những đặc điểm, hành vi chung của con người:
Tiếp theo ta tạo một lớp con kế thừa lại lớp cha và đó là lớp Student
Như bạn đã thấy, chúng ta cũng có thể thêm những đặc điểm, method riêng mà chỉ học sinh mới có, điều nay cũng giúp ta tránh bị lặp code.
Để có thể hiểu sâu hơn, tính kế thừa được chia ra làm 4 loại:
- Đơn kế thừa (Single Inheritance)
Đối với Đơn kế thừa, một lớp sẽ kế thừa những thuộc tính của một lớp khác. Nó cho phép một lớp con kế thừa những thuộc tính và hành vi (method) từ một lớp cha.
Điều này sẽ cho phép code khả năng tái sử dụng code cũng như thêm các tính năng mới vào các đoạn code hiện có.
Ở ví dụ bên trên, Class Person là lớp cha và Class Student là lớp con với những thuộc tính và hành vi của lớp cha.
- Kế thừa đa cấp (Multilevel Inheritance)
Khi một lớp được bắt nguồn từ một lớp mà cũng là lớp con (kế thừa từ một lớp khác). Tức là một lớp có nhiều hơn một cấp cha, kiểu kế thừa đó được gọi là kế thừa kiểu đa cấp.
Vẫn tiếp tục ở ví dụ trên, nếu bây giờ ta tạo ra một lớp dành cho đối tượng học sinh giỏi thì sẽ extends lại lớp Student, lúc này class Student là lớp cha và class Person là lớp ông của lớp AdvancedStudent
- Kế thừa thứ bậc (Hierarchical Inheritance)
Khi một lớp có nhiều hơn một lớp con hoặc nói cách khác là có nhiều hơn một lớp con có cùng chung một lớp cha, lúc này loại kế thừa này được gọi là thứ bậc (hierarchical).
- Kế thừa lai (Hybrid Inheritance)
Để tránh sự phức tạp, Java không hỗ trợ sự đa kế thừa giữa các Class với nhau. Tuy nhiên, vẫn có cách để chúng ta đạt được sự đa kế thừa đó là sử dụng Interface thông qua từ khóa Implements.
Ví dụ như sau: Mỗi lớp trên đều có điểm chung là thuộc tính và hành vi, vậy thì mình sẽ tách riêng ra để có thể thực hiện kế thừa lai.
Ví dụ trên đã tạo ra 3 interface là
- IStudy (gồm những method cơ bản của một học sinh)
- IDev (gồm những môn bắt buộc của một học sinh CNTT)
- IAdvanced (gồm môn học của một học sinh giỏi)
Sau đó ta sẽ cho các lớp đối tượng sinh viên implement những interface cần thiết để có thể sử dụng.
Như vậy ta đã có thể giải quyết được vấn đề đơn kế thừa trong Java rồi đúng không. Qua những ví dụ trên mong các bạn hiểu được tính chất đầu tiên này trong OOP.
Trong bài viết tiếp theo, chúng ta sẽ đi tới tính chất thứ hai trong OOP đó là tính đóng gói.
Tâm pháp tầng thứ hai : Encapsulation
Tính đóng gói là một cơ chế liên kết dữ liệu và code chung với nhau thành một đơn vị duy nhất. Nó cũng được hiểu với mục đích che giấu dữ liệu của bạn để đảm bảo toàn vẹn dữ liệu từ những chỉnh sửa bên ngoài.
Tính đóng gói có 4 kiểu phạm vi truy cập (Access Modifier) như sau:
- Default(mặc định): Nếu như bạn không khai báo phạm vi truy cập, Java sẽ hiểu mặc định phạm vi truy cập là default. Với default thì trong lớp (class) đó và trong gói (package) đó mới có thể nhìn thấy được.
- Private(riêng tư): Nếu như bạn khai báo phạm vi truy cập là private, chỉ có thể sử dụng ở ngay trong chính lớp đó thôi.
- Public(công khai): Nếu như bạn khai báo ở dạng public, mọi thông tin trong lớp đó đều có thể được nhìn thấy từ các lớp (class), các gói (package), hay là class con (subclass)
- Protected(được bảo vệ) : Nếu bạn khai báo ở dạng này, lớp (class) đó, gói (package) đó, lớp con (subclass) đó đều có thể thấy được.
Note: Có thể nhiều bạn sẽ hiểu lầm về public và protected nhưng phạm vi của pubic nó rất rộng, bạn có thể truy cập vào 1 class với các thuộc tính được public từ package này sang package khác, còn protected thì không, nó chỉ hoạt động trong chính package của nó mà thôi.
Để dễ hiểu thì các bạn có thể xem ví dụ ở dưới đây:
Code ở trên cơ bản là không sai, nó vẫn chạy và diễn ra bình thường, nhưng nó dễ dàng xảy ra sự cố bị thay đổi dữ liệu. Để giải quyết vấn đề đó, ta cần phải private hết dữ liệu lại để tránh bị sửa code từ những tác nhân bên ngoài. Bên cạnh đó, để truy cập được từ class khác, Java có thêm 2 phương thức thần kỳ đó chính là Getter và Setter, hai phương thức này chuyên dùng để có thể lấy và ghi dữ liệu.
Như vậy từ lần sau, chúng ta nên khai báo một lớp với những phạm vi truy cập ở dạng private để có thể bảo toàn dữ liệu và truy cập tới chúng thông qua phương thức Get và Set.
Đây được gọi là Constructor không tham số, Constructor này sẽ luôn được mặc định gọi ra kể cả khi bạn có khai báo hay không. Ngoài Constructor không tham số ta cũng có Constructor có tham số, riêng Constructor có tham số thì bắt buộc bạn phải khai báo. Constructor có tham số có nhiệm vụ giống với Get và Set, bạn có thể truyền dữ liệu vào đó mà không cần Get và Set.
Như vậy là các bạn đã hiểu về tính chất thứ 2 trong OOP rồi, tiếp theo ta sẽ đến với tính chất thứ 3 đó là tính trừu tượng.
- Tâm pháp tầng thứ ba: Abstraction
Tính trừu tượng là một tiến trình ẩn các chi tiết trình triển khai và chỉ hiển thị tính năng tới người dùng. Tính trừu tượng cho phép bạn loại bỏ tính chất phức tạp của đối tượng bằng cách chỉ đưa ra các thuộc tính và phương thức cần thiết của đối tượng trong lập trình.
Có hai cách để ta có thể triển khai được tính trừu tượng:
- Sử dụng Abstract Class
- Sử dụng Interface
Abstract Class
Một lớp được khai báo với từ khóa abstract tức là một lớp abstract. Lúc này bạn sẽ không thể sử dụng từ khóa “new”, có nghĩa là bạn không thể tạo instance từ một lớp trừu tượng. Cách duy nhất đó là dùng một lớp con kế thừa lại lớp abstract class.
Để dễ hiểu mình có ví dụ như sau:
Đầu tiên ví dụ trê có tạo ra một abstract class với phương thức rỗng là draw(), Sau đó tạo thêm một lớp con là Rectangle kế thừa lại lớp Shape để sử dụng lại method. Kết quả:
Lúc này lớp abstract đóng vai trò như một base class, khai báo tất cả những method cơ bản và cần thiết nhất để các lớp khác có thể tái sử dụng mà không cần viết lại code. Tuy nhiên khi ta extends một class Abstract, ta phải Override lại toàn bộ methods đã được khai báo.
Interface
Trong Interface thì chỉ có thể khai báo các method rỗng (tức không có body code) để các lớp khác khi implements sẽ khai báo và sử dụng lại methods đó. Tuy nhiên khi lên Java 8 thì Interface được hỗ trợ defaults methods, lúc này bạn có thể triển khai body code trong một Interface. Để hiểu rõ hơn về defaults methods bạn có thể đọc bài viết này:
Abstract Class | Interface |
Thể hiện tính trừu tượng <100% | Thể hiện tính trừu tượng 100% (< Java 8) |
Lớp trừu tượng không hỗ trợ đa kế thừa | Interface có hỗ trợ đa kế thừa |
Lớp trừu tượng có thể có phương thức static, phương thức main và constructor. | Không có phương thức static, phương thức main và constructor. |
Từ khóa abstract để khai báo một lớp abstract | Từ khóa interface để khai báo một lớp Interface. |
Lớp trừu tượng có thể cung cấp trình triển khai của một Interface | Interface không thể cung cấp trình triển khai cụ thể của lớp abstract. |
Cuối cùng là tính chất thứ 4, tính đa hình.
- Tâm pháp tầng thứ tư : Polymorphism
Trong tiếng Anh, “poly” nghĩa là nhiều, “morph” có nghĩa là hình thức. Đa hình có thể là một biến, một chức năng, một đối tượng được đưa vào sử dụng dưới nhiều hình thức khác nhau.
Trước mắt ta phải hiểu rõ, khi nói đến đa hình là phải đi kèm với kế thừa. Bởi vì để một đối tượng nào đó có thể nhập vai vào một đối tượng khác thù chỉ có thể một đối tượng cha, và ở đây lớp cn sẽ phải ghi đè (Overriding) lại các phương thức của lớp cha.
Ta hãy cùng xem ví dụ dưới đây:
Ngoài ra ta còn có Overloading để thể hiện tính đa hình. Vậy sự khác biệt giữa Overriding và Overloading là gì?
- Overloading (nạp chồng) đây là khả năng cho phép một lớp có nhiều thuộc tính, phương thức cùng tên nhưng với các tham số khác nhau về loại cũng như về số lượng. Khi được gọi, dựa vào tham số truyền vào, phương thức tương ứng sẽ được thực hiện.
- Overriding (ghi đè) là hai phương thức cùng tên, cùng tham số, cùng kiểu trả về nhưng thằng con viết lại và dùng theo cách của nó, và xuất hiện ở lớp cha và tiếp tục xuất hiện ở lớp con. Khi dùng override, lúc thực thi, nếu lớp Con không có phương thức riêng, phương thức của lớp Cha sẽ được gọi, ngược lại nếu có, phương thức của lớp Con được gọi.
Để dễ hiểu các bạn có thể hiểu Overloading như sau: Nếu một lớp có nhiều phương thức cùng tên nhưng khác nhau về tham số hay kiểu dữ liệu thì đó chính là nạp chồng phương thức.
Như vậy bài viết này đã giới thiệu thêm cho các bạn về tính chất trong OOP. Hy vọng bài viết này sẽ giúp các bạn sinh viên Cao đẳng FPT Mạng cá cược bóng đá có cái nhìn bao quát hơn về lập trình hướng đối tượng, từ đó sẽ giúp các bạn hiểu rõ hơn về những kiến thức bao la phía sau.
Bộ môn Ứng dụng phần mềm
Cao đẳng FPT Mạng cá cược bóng đá
Hà Nội