Bạn đang tìm kiếm công việc lập trình viên thì có thể bạn nên biết rằng một câu hỏi mà bất cứ nhà tuyển dụng lập trình nào cũng sẽ sử dụng nếu ứng viên muốn có được một vị trí trong công ty, đó là : Các nguyên tắc chính của lập trình hướng đối tượng là gì? Đây là 1 trong số 3 câu hỏi lớn mà khi tôi phỏng vấn tại công ty lập trình website / phần mềm Mona Media đã tuyển dụng tôi lúc đấy.
Đây là một câu hỏi phổ biến đến nỗi mà nếu không biết câu trả lời, coi như bạn nắm chắc một vé ra về. Vậy thì lập trình hướng đối tượng (OOP) là gì? Bài viết dưới đây sẽ cho bạn một cái nhìn tổng quan về lập trình hướng đối tượng, cũng như 4 tính chất của lập trình hướng đối tượng.
Lập trình hướng đối tượng là gì?
Lập trình hướng đối tượng (OOP) là cách viết chương trình máy tính bằng cách sử dụng ý tưởng “đối tượng” để biểu diễn dữ liệu và phương thức. Thông thường, các chương trình máy tính chỉ là một danh sách các bước hướng dẫn và yêu cầu máy tính thực hiện một số việc theo một cách nhất định, được gọi là lập trình thủ tục. Tuy nhiên, trong lập trình hướng đối tượng, các chương trình máy tính sử dụng các đối tượng giao tiếp với nhau và để thay đổi dữ liệu trong các đối tượng đó, sao cho nó hoạt động theo cách mà người dùng muốn. Ngoài ra, lập trình hướng đối tượng giúp developer viết code dễ dàng hơn và cho phép các phần khác của chương trình được quyền sử dụng lại hoặc thậm chí cho người khác sử dụng lại.
Hầu hết các ngôn ngữ lập trình là sự pha trộn của nhiều cách viết chương trình máy tính khác nhau. Ví dụ, Python cho phép các chương trình máy tính được viết cả trong lập trình hướng đối tượng và lập trình thủ tục. Có nhiều ngôn ngữ lập trình cho phép bạn viết chương trình máy tính trong OOP như là C#, C++, Java, Ruby, Perl, PHP, v.v.
4 tính chất của lập trình hướng đối tượng
Sau đây là 4 tính chất của lập trình hướng đối tượng (OOP): đóng gói (encapsulation), trừu tượng (abstraction), kế thừa (inheritance) và đa hình (polymorphism).
Tính đóng gói (Encapsulation):
Ví dụ chúng ta đang có một chương trình. Nó có một vài đối tượng khác nhau giao tiếp với nhau – theo các quy tắc được xác định trong chương trình.
Chúng ta đạt được tính chất đóng gói khi mỗi đối tượng giữ trạng thái riêng tư, nằm bên trong một lớp (class). Các đối tượng khác không có quyền truy cập trực tiếp vào các lớp này. Thay vào đó, họ chỉ có thể gọi một danh sách các hàm công khai – được gọi là các phương thức.
Vì vậy, đối tượng quản lý trạng thái của chính nó thông qua các phương thức – và không có lớp nào khác có thể chạm vào nó trừ khi được cho phép. Nếu bạn muốn giao tiếp với đối tượng, bạn nên sử dụng các phương thức được cung cấp. Tuy nhiên theo mặc định, bạn không thể thay đổi các trạng thái này.
Ví dụ, chúng ta xây dựng game Sims đơn giản, bao gồm con người và một con mèo. Chúng giao tiếp với nhau. Chúng ta áp dụng tính chất đóng gói, tức là gói gọn tất cả logic của đối tượng “mèo” vào lớp Mèo như hình dưới đây:
Ở đây, “trạng thái” của con mèo là các biến riêng tư: tâm trạng, mức độ đói bụng và năng lượng. Nó cũng có một phương thức riêng là meo meo(). Nó có thể kêu meo meo bất cứ khi nào nó muốn, các lớp khác không thể nói con mèo kêu meo meo vào lúc nào cả.
Những gì mà các phương thức công cộng có thể làm được định nghĩa trong các phương thức công khai ngủ (), chơi () và cho ăn(). Mỗi phương thức công cộng có thể tự sửa đổi trạng thái nội bộ của nó bằng cách nào đó và để con mèo có thể kêu meo meo (). Do đó, sự ràng buộc giữa phương thức riêng và phương thức công cộng được thực hiện.
Tính trừu tượng
Tính chất trừu tượng được coi là phần mở rộng của tính chất đóng gói.
Trong thiết kế hướng đối tượng, các chương trình được xây dựng trên nó cực kỳ lớn. Các đối tượng riêng biệt được giao tiếp với nhau rất nhiều. Vì vậy, rất khó để có thể thay đổi các code này, nhất là khi chương trình đã được xây dựng trong nhiều năm, mọi thứ đều đã được kết nối với nhau. Tính chất trừu tượng sinh ra để giải quyết vấn đề này. Áp dụng tính chất này, mỗi đối tượng chỉ nên đưa ra một cơ chế cấp cao. Cơ chế này sẽ ẩn chi tiết thực hiện nội bộ. Nó chỉ tiết lộ các hoạt động liên quan cho các đối tượng khác.
Ví dụ như một chiếc máy pha cà phê. Nó hoạt động dựa trên các máy móc bên trong nó, chúng ta chỉ cần công đoạn bỏ cà phê và bấm nút là xong. Tương tự như trong lập trình, cơ chế này nên được lập trình sao cho dễ sử dụng. Nó giống như là một tập hợp nhỏ các phương thức công khai mà bất kỳ lớp nào có thể gọi mà không cần biết về cách thức hoạt động của chúng.
Một ví dụ thực tế khác, hãy suy nghĩ về cách bạn sử dụng điện thoại:
Bạn tương tác với smartphone qua các nút bấm và màn hình cảm ứng. Còn những thứ xảy ra bên trong nó bạn chẳng cần biết. Bạn chỉ cần thao tác bằng tay là đủ.
Tính thừa kế (inheritance)
Ok, chúng ta đã thấy tính chất đóng gói và trừu tượng được áp dụng như thế nào. Chúng giúp ta phát triển và duy trì một cơ sở mã lớn. Nhưng bạn có biết một vấn đề phổ biến khác trong OOP là gì không?
Các đối tượng thường giống nhau. Chúng chia sẻ chung hệ logic. Tuy nhiên, chúng không hoàn toàn giống nhau. Làm để chúng ta có thể tái sử dụng logic thông thường và trích xuất logic duy nhất vào 1 class riêng biệt? Một cách để đạt được điều này chính sử dụng tính thừa kế.
Chúng ta tạo ra một lớp (con) xuất phát từ một lớp (cha) khác. Bằng cách này, chúng ta tạo ra một hệ thống phân cách. Lớp con sử dụng lại tất cả các trường và phương thức của lớp cha (phần logic chung) để thực hiện phần riêng của nó (phần logic riêng).
Ví dụ: Bạn đang giữ một lá đơn trong tay của bạn, đặt tên là thông tin cá nhân 1.
Họ : _______
Tên: _______
Bạn photocopy ra một bản giống như vậy nhưng đặt tên là Thông tin cá nhân 2. Có nghĩa là bản thứ 2 này được thừa kế thông tin từ bảng thứ 1.
Bây giờ bạn muốn tạo ra một lá đơn bao gồm họ, tên và ngày sinh. Thay vì tạo mới và gõ chữ lại cho bản Thông tin cá nhân 3, bạn chỉ cần đến chỗ máy photo và thêm dòng thông tin ngày sinh: _/_/_ vào. Có nghĩa rằng bạn đã thừa kế từ lá đơn Thông tin cá nhân 1 và tạo ra một tái bản bổ sung Ngày sinh vào.
Tính đa hình (polymorphism)
Chúng ta hãy đi ngay đến ví dụ. Bạn nói với 1 ai đó rằng: “Hãy đến cửa hàng và mua một số thực phẩm yêu thích của bạn cho bữa tối.”
Nếu bạn nói với đứa con trai 14 tuổi của bạn, có thể nó đã chạy ra ngoài và trả tiền mặt cho món pizza mà nó thích. Trong khi nếu là vợ bạn thì có thể cô ấy sẽ mua một món khác chẳng hạn.
Trong một chương trình, mọi thứ diễn ra hơi giống nhau: bạn chỉ định một cái gì đó ở mức tương đối trừu tượng (đi đến cửa hàng và nhận bữa ăn tối). Mỗi đối tượng cung cấp cách triển khai cụ thể của riêng mình về cách thực hiện điều đó (ví dụ, như sự khác biệt trong các loại thực phẩm yêu thích ở trên).
Tất nhiên, khi bạn lập trình, hầu hết điều đó đòi hỏi một đặc tả chi tiết hơn và rõ ràng hơn nhiều. Ý tưởng chung vẫn giữ nguyên. Đối với kịch bản ở trên, bạn có thể có một lớp cơ sở cá nhân (hoặc giao diện) xác định các phương thức như đi đến cửa hàng và chọn thực phẩm yêu thích và trả tiền mua hàng. Sau đó, bạn sẽ có những triển khai như đứa con trai và người vợ, mỗi người trong số họ xác định phương pháp đi đến cửa hàng, chọn thực phẩm yêu thích và trả tiền mua hàng. Những phương thức đó sẽ là đa hình, bởi vì mỗi cách thực hiện sẽ có cách riêng để thực hiện lệnh cấp cao hơn mà bạn đã đưa ra.
Trên đây là một số kiến thức và định nghĩa ở mức chung nhất về Lập trình hướng đối tượng. Đối với riêng mỗi ngôn ngữ lập trình hướng đối tượng như C++ hay Java, ta lại có những cú pháp riêng và cách giải thích khác nhau. Tuy nhiên nhìn chung thì chúng vẫn bao gồm những kiến thức cơ bản trên, với lập trình C++ thì bạn có thể tham khảo nhiều tài liệu hướng dẫn tại trang visualcpp.net, giới thiệu về cú pháp và các code editor để hỗ trợ lập trình tốt hơn.