Giới thiệu về lập trình hướng đối tượng (OOP)

11-05-2024


Trong thế giới phát triển phần mềm ngày nay, việc xây dựng các ứng dụng mạnh mẽ và linh hoạt đòi hỏi phải sử dụng các phương pháp và công nghệ tiên tiến nhất. Trong số đó, lập trình hướng đối tượng (OOP) đã trở thành một trong những công cụ quan trọng nhất cho các nhà phát triển phần mềm.

Bài viết này sẽ đi sâu vào khám phá về lập trình hướng đối tượng, từ việc hiểu rõ các hạn chế của lập trình truyền thống đến những ưu điểm của lập trình hướng đối tượng, lớp và đối tượng, thuộc tính và phương thức, khai báo và sử dụng lớp - đối tượng, giúp cải thiện quy trình phát triển phần mềm và tạo ra các ứng dụng mạnh mẽ hơn.

1. Hạn chế của lập trình truyền thống:

Trước khi đi vào lập trình hướng đối tượng, chúng ta cần hiểu rõ về những hạn chế của lập trình truyền thống. Lập trình truyền thống thường gặp phải các vấn đề như mã nguồn rối rắm, khó hiểu và khó bảo trì, do thiếu cơ chế tổ chức mã nguồn. Hơn nữa, việc tái sử dụng mã nguồn không được ưu tiên, dẫn đến việc tạo ra mã nguồn lặp lại và khó bảo trì.

            1.1 Khó khăn trong việc quản lý mã nguồn:

Lập trình truyền thống thường không có cơ chế cụ thể để tổ chức mã nguồn một cách có hệ thống, đặc biệt là khi xử lý các chức năng phức tạp. Khi mã nguồn trở nên lớn và phức tạp, việc duy trì và quản lý trở nên khó khăn, dẫn đến việc khó tìm kiếm và sửa lỗi.

Ví dụ:

Một trang web có thể có các tệp tin riêng biệt cho việc đăng nhập, đăng ký, hiển thị thông tin người dùng, và những chức năng khác. Mỗi tệp tin này thường chứa một loạt các hàm và đoạn mã thực thi chức năng tương ứng.

Tuy nhiên, khi ứng dụng phát triển, số lượng chức năng và tệp tin có thể tăng lên đáng kể. Mỗi tệp tin có thể chứa hàng trăm hoặc thậm chí hàng nghìn dòng mã. Điều này dẫn đến mã nguồn rối rắm và khó tái sử dụng

            1.2 Thiếu tính tái sử dụng:

Trong lập trình truyền thống, việc tái sử dụng mã nguồn không được ưu tiên. Mỗi chức năng thường được triển khai một cách riêng lẻ mà không có cơ chế nào để chia sẻ và sử dụng lại code. Điều này dẫn đến việc lặp lại mã nguồn và làm tăng thời gian và công sức cần thiết cho việc phát triển và bảo trì mã nguồn.

Ví dụ:

Trong ứng dụng của chúng ta, có một yêu cầu là phải tính toán giá trị tổng số tiền các sản phẩm trong giỏ hàng của người dùng. Để làm điều này, chúng ta viết một phương thức để lặp qua danh sách các sản phẩm trong giỏ hàng và tính tổng số tiền

Tuy nhiên, sau đó, chúng ta nhận được một yêu cầu mới: cần tính toán giảm giá cho giỏ hàng dựa trên các khuyến mãi hiện có. Điều này có nghĩa là chúng ta cần phải tính toán tổng số tiền với giảm giá được áp dụng.

Để giải quyết vấn đề này, có thể viết một phương thức mới trong lớp ShoppingCart để tính toán tổng số tiền với giảm giá, nhưng điều này sẽ dẫn đến sự lặp lại của mã nguồn, vì chúng ta đã có một phương thức calculateTotalPrice() đã tính toán tổng số tiền trước khi áp dụng giảm giá.

Trong trường hợp này, thiếu tính tái sử dụng dẫn đến việc phải viết lại mã nguồn, tạo ra sự lặp lại không cần thiết và làm giảm sự hiệu quả của quá trình phát triển ứng dụng.

Để khắc phục hạn chế này, chúng ta có thể tạo một phương thức chung để tính toán tổng số tiền, nhưng có thêm một tham số cho giảm giá, từ đó chúng ta có thể tái sử dụng mã nguồn một cách hiệu quả và tránh sự lặp lại.

1.3 Hạn chế trong quản lý trạng thái:

Trong lập trình truyền thống, việc quản lý trạng thái của ứng dụng thường trở nên phức tạp và dễ gây lỗi. Mỗi chức năng thường thay đổi trạng thái của biến và dữ liệu một cách tùy ý, làm cho việc theo dõi và xử lý các lỗi liên quan đến trạng thái trở nên khó khăn.

1.4 Khó khăn trong việc mở rộng và phát triển:

Lập trình truyền thống thường không có cơ chế linh hoạt để mở rộng và phát triển ứng dụng một cách dễ dàng. Khi yêu cầu thay đổi, việc cập nhật và mở rộng chương trình thường đòi hỏi sự thay đổi lớn trong mã nguồn, làm tăng nguy cơ phá vỡ và gây ra các lỗi không mong muốn.

Ví dụ:

Giả sử bạn đang phát triển một ứng dụng web đơn giản để quản lý danh sách sản phẩm của một cửa hàng trực tuyến. Ban đầu, ứng dụng chỉ có các chức năng cơ bản như hiển thị danh sách sản phẩm và cho phép người dùng thêm mới sản phẩm.

Tuy nhiên, sau một thời gian, cửa hàng quyết định mở rộng chức năng bằng cách thêm tính năng giỏ hàng và thanh toán trực tuyến. Trong một ứng dụng lập trình truyền thống, việc thêm tính năng này có thể gây ra một số vấn đề:

Thay đổi cấu trúc mã nguồn: Thêm tính năng giỏ hàng và thanh toán có thể yêu cầu sửa đổi sâu vào cấu trúc hiện có của ứng dụng. Bạn có thể cần phải thêm các lớp mới, sửa đổi các phương thức hoặc thậm chí thay đổi cơ sở dữ liệu.

Nguy cơ phá vỡ chức năng khác: Việc thêm tính năng mới có thể ảnh hưởng đến các phần khác của ứng dụng. Ví dụ, việc thêm giỏ hàng có thể làm thay đổi giao diện người dùng, và điều này có thể gây ra lỗi trong phần hiển thị danh sách sản phẩm.

Khó khăn trong bảo trì: Mã nguồn sau khi thêm tính năng mới có thể trở nên phức tạp và khó hiểu hơn, làm cho việc bảo trì trở nên khó khăn hơn. Các lập trình viên mới có thể gặp khó khăn trong việc hiểu cấu trúc và logic của ứng dụng

 

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

Lập trình hướng đối tượng (Object Oriented Programing – OOP) là một phương pháp để thiết kế một chương trình bởi sử dụng các lớp và các đối tượng.

Lập trình hướng đối tượng tập trung vào việc mô hình hóa thế giới thực bằng cách định nghĩa các đối tượng có tính chất và hành vi riêng. Mỗi đối tượng là một phiên bản của một lớp, và nó bao gồm các thuộc tính và phương thức để mô tả hành vi của nó. Việc sử dụng lớp và đối tượng trong lập trình hướng đối tượng giúp tạo ra mã nguồn có tổ chức, dễ bảo trì và mở rộng.

            2.1 Ưu điểm của phương pháp lập trình hướng đối tượng

           Nâng cao hiệu năng phát triển phần mềm:

           Ba yếu tố quan trọng của lập trình hướng đối tượng là:

- Tính mô-đun: nó tách biệt các nhiệm vụ trong quá trình phát triển phần mềm dựa trên những đối tượng cụ thể. Mỗi đối tượng sẽ có một nhiệm vụ khác nhau.

- Tính mở rộng: các đối tượng có thể được mở rộng dễ dàng, bao gồm mở rộng thuộc tính và các hành vi mới.

- Tính tái sử dụng: các đối tượng cũng có thể được sử dụng lại trong một ứng dụng hoặc nhiều ứng dụng khác nhau.

Ba yếu tố trên của lập trình hướng đối tượng giúp hiệu năng phát triển phần mềm cũng được cải thiện rất nhiều, so với kỹ thuật lập trình truyền thống dựa trên thủ tục.

Dễ bảo trì và mở rộng: Kiến trúc của lập trình hướng đối tượng làm cho việc bảo trì và mở rộng ứng dụng trở nên dễ dàng hơn. Các đối tượng có thể được sửa đổi hoặc thay thế mà không ảnh hưởng đến các phần khác của hệ thống, giúp giảm thiểu rủi ro phá vỡ và tiết kiệm chi phí bảo trì.

 

Tiết kiệm thời gian và chi phí phát triển: Do tính tái sử dụng mã nguồn cao và khả năng kế thừa của lập trình hướng đối tượng, các dự án phần mềm thường có thể được phát triển nhanh chóng hơn và với chi phí thấp hơn. Việc sử dụng các thành phần và lớp đã được xây dựng trước giúp giảm thiểu việc viết lại mã nguồn từ đầu và tăng hiệu quả trong quá trình phát triển.

 

 

2.2 Lớp và đối tượng

 

Đối tượng (object):

Đối tượng là một thực thể có thuộc tính và hành vi. Nó có thể mang tính vật lý hoặc logic và mọi thực thể đều có thể được mô tả như một đối tượng.

Thuộc tính (atribute): Là các biến hoặc dữ liệu được liên kết với một đối tượng cụ thể. Thuộc tính định nghĩa các đặc điểm, trạng thái hoặc thông tin về đối tượng mà đối tượng đó có thể có. Ví dụ, một đối tượng "Cat" có thể có các thuộc tính như: "màu sắc", "cân nặng", "giống mèo", vv.

Hành vi : là các hoạt động hoặc hành động mà một đối tượng có thể thực hiện. Hành vi định nghĩa cách mà đối tượng phản ứng và tương tác với các yêu cầu hoặc thao tác từ bên ngoài. Gọi tắt là phương thức (method). Ví dụ, một đối tượng “Cat” có thể có các phương thức như: “kêu meo meo”, “nghỉ ngơi”, “di chuyển”, vv.

Ví dụ về đối tượng: Cái bàn, bình nước, cái bảng,  con người… Tất cả những đối tượng trên đều có thuộc tính và hành vi

Nếu chúng ta xem xét một con chó, thuộc tính của nó sẽ là – “tên”, “giống”, màu sắc, và các hành vi là: “sủa”, “chạy”, “ăn”, … Nếu là một chiếc ô tô thì thuốc tính sẽ là “màu sắc”, “tên hãng”, “giá xe”… và các hành vi là “bíp còi”, “tăng tốc”, “hạ kính xe”…

 

Lớp (class):

Trong lập trình hướng đối tượng, một lớp (class) là một mẫu (template) hoặc một khuôn mẫu cho việc tạo ra các đối tượng cùng loại (objects). Lớp định nghĩa các thuộc tính (attributes) và các phương thức (methods) mà một đối tượng cụ thể của lớp đó có thể có.

Trong ví dụ trên Class đã định nghĩa mô hình của một chiếc xe ô tô và từ mô hình đó ta có thể tạo ra các đối tượng ô tô với màu sắc, kiểu dáng và các tính năng khác nhau.

Ô tô của Xuân và của đông về bản chất đều là ô tô nên đều có các trường “Hãng sx”, “Model”, “Màu sơn”, “Năm sản xuất”. Nhưng vì là 2 đối tượng khác nhau nên giá trị của các trường sẽ khác nhau ví dụ: ô tô của Xuân hãng “Vinfast” còn ô tô của Đông hãng “Honda”

 

Khai báo:

<Phạm vi truy cập> class <Tên lớp> {      

       // Khai báo thuộc tính (field) hay biến     

       <Phạm vi truy cập> <kiểu dữ liệu> <field_1>;      

       <Phạm vi truy cập> <kiểu dữ liệu> <field_2>;  

    

       // Hàm khởi tạo không có tham số     

       <Phạm vi truy cập> <Tên lớp>(){         

       // Khởi tạo dữ liệu     

       }     

 

       // Hàm khởi tạo có tham số     

       <Phạm vi truy cập> <Tên lớp>(<Kiểu dữ liệu> <tên biến>[,<Kiểu dữ liệu> <tên biến>]){         

       // Khởi tạo dữ liệu     

       }     

       // Phương thức xử lý (method)     

       <Kiểu trả về> method_1() {         

       // Logic xử lý      

       }     

       <Phạm vi truy cập> <Kiểu trả về> method_2(<Kiểu dữ liệu> <tên biến>) {         

       // Logic xử lý      

       }

}

 

      Trong đó:

    • Phạm vi truy cập xác định ai có quyền truy cập vào các thành phần đó và ở đâu có thể truy cập chúng.
    • class: là từ khóa để khai báo lớp trong Java.
    • Tên lớp: là tên chúng ta đặt cho lớp (quy tắc đặt tên: viết hoa mỗi chữ cái đầu).
    • field_1, field_2: các thuộc tính, các biến, hay các thành phần dữ liệu của lớp (quy tắc đặt tên: chữ cái đầu tiên viết thường, các chữ cái đầu tiên tiếp theo viết hoa).
    • Hàm khởi tạo (constructor): hàm dùng để khởi tạo đối tượng lớp, hàm khởi tạo sẽ được gọi đầu tiên khi đối tượng được khởi tạo
    • method_1, method_2: là các phương thức thể hiện các thao tác xử lý, tác động lên các thành phần dữ liệu của lớp.

 

Ví dụ: Tạo Class NhanVien

    • Với các thuộc tính: name, id và HSL
    • Tạo hàm khởi tạo có tham số là id, name.
    • Cung cấp 3 phương thức: lấy id, lấy name, lấy hệ số lương và gán giá trị HSL

 

Sử dụng lớp:

<Tên lớp> <tên đối tượng> = new <Tên lớp>(<giá trị tham số nếu có>);

<tên đối tượng>.<tên thuộc tính>;

<tên đối tượng>.<tên phương thức>(<giá trị tham số nếu có>);

 

    - Toán tử new được dừng để tạo đối tượng.

    - Sử dụng dấu chấm (.) để truy xuất đến các thành phần của lớp (trường và phương thức).

Ví dụ:

 

Có thể thấy rằng lập trình hướng đối tượng là một trong những quá trình vô cùng quan trọng và không thể thiếu của mỗi lập trình viên. Trên đây, chúng tôi đã giới thiệu qua cho các bạn về OOP. Mặc dù chúng là những kiến thức cơ bản, nhưng hầu hết các lập trình viên khi bước chân vào con đường lập trình thì đều cần phải học. Hy vọng rằng, bài viết này sẽ giúp bạn có thể tiếp cận gần hơn với OOP. Hãy liên hệ với chúng tôi nếu bạn có bất kỳ những thắc mắc hay câu hỏi nào liên quan đến lập trình hướng đối tượng nhé!