1. Lập trình hướng đối tượng (Oriented Object Programming – OOP) là gì?
- Lập trình hướng đối tượng là một mô hình lập trình máy tính dựa trên khái niệm lớp và đối tượng.
- Lấy đối tượng làm nền tảng để xây dựng thuật giải, xây dựng chương trình và thực hiện xử lý dữ liệu với đối tượng đã định nghĩa đó.
- Nhằm tối ưu hóa việc quản lý mã nguồn (source code), tái sử dụng mã nguồn, tóm gọn các thủ tục đã biết trước tính chất thông qua việc sử dụng đối tượng.
- Một đối tượng có thể được định nghĩa là một trường dữ liệu có các thuộc tính và các hành động của riêng nó:
Ví dụ 1
// 1 ví dụ đơn giản về định nghĩa lớp đối tượng *phương trình bậc 2* ax^2 + bx + c = 0 trong java:publicclass PTB2 {// Khai báo các thuộc tính của một phương trình bậc 2 gồm các hệ số thực a, b, cprivatedouble a, b, c;// Khai báo các phương thức hay hành động có thể làm của lớp đối tượng này// Tính deltapublicdoubledelta(){return b * b -4* a * c;}// Tìm nghiệm trong tập số thực R và in ra màn hìnhpublicvoidtimNo(){// Tính và lưu giá trị delta vào một biếndouble dt =delta();// Xét điều kiện ( bao gồm delta và hệ số a ) và tiến hành tìm nghiệmif(a ==0){/* Chúng ta chỉ xét nhập vào một phương trình bậc 2 và giải nghiệm chẳng hạn,
nên khi người dùng nhập a = 0 chúng ta sẽ hiển thị thông báo như sau. ^^*/System.out.println("- Phương trình bậc 2 phải có hệ số a khác 0.");}else{if(dt <0)System.out.println("- Phương trình vô nghiệm.");elseif(dt ==0){System.out.printf("- Phương trình có nghiệm kép x1 = x2 = %.3fn",-b /2* a);}else{System.out.println("- Phương trình có 2 nghiệm phân biệt:");System.out.printf("tx1 = %.3fn",(-b +sqrt(dt))/2* a);System.out.printf("tx2 = %.3fn",(-b -sqrt(dt))/2* a);}}/* Cùng với đó là các hàm khởi tạo (constructor), hay các setter, getter
hoặc chúng ta có thể tự định nghĩa thêm các hành động nhập xuất phù hợp
với bài toán yêu cầu*/publicPTB2(double a,double b,double c){this.a = a;this.b = b;this.c = c;}publicdoublegetA(){return a;}publicvoidsetA(double a){this.a = a;}publicdoublegetB(){return b;}publicvoidsetB(double b){this.b = b;}publicdoublegetC(){return c;}publicvoidsetC(double c){this.c = c;}//...}}
2. Các thành phần của OOP
- Lớp (class): Là sự trừu tượng hóa của đối tượng. Là khuân mẫu của một tập hợp các đối tượng có cùng thuộc tính (attributes) và hành vi (methods). Cấu trúc của 1 lớp gồm:
- Phạm vi truy cập (access modifier): phạm vi truy cập của lớp, của thuộc tính và phương thức. (private, protected, default, public)
- Tên lớp (class name): Mỗi lớp đều có một tên riêng biệt, để phân biệt với các lớp khác trong cùng một phạm vi.
<access modifier>class<class name>{}
- Các thuộc tính (attributes): Mô tả các trường để lưu dữ liệu cho mỗi đối tượng mà lớp đang định nghĩa hay lưu các tham chiếu đến đối tượng của lớp khác.
Ví dụ 2: ta có 2 lớp đối tượng A và B, giờ ta muốn tham chiếu 1 đối tượng x từ lớp B trong lớp đối tượng A chẳng hạn, và đây những gì được viết trong class A
publicclassA{// Các trường lưu dữ liệu cho mỗi đối tượng:privateint y, z;// Tham chiếu đến đối tượng x từ lớp BprivateB x;}
- Các phương thức (methods): mỗi phương thức của lớp thực chất là một hàm được viết riêng cho các đối tượng của lớp, và được gọi đến để tác động lên các đối tượng của lớp đó.
ví dụ 3:
// Lớp ErrpublicclassErr{// Các thuộc tínhprivateString title;privateString mess;// Phương thứcpublicvoidinputData(String tt,String m){ title = tt; mess = m;}publicvoidoutput(){System.out.println("Err "+ title +": "+ mess);}}// Hàm mainpublicstaticvoidmain(String args[]){// Khai báo, khởi tạo đối tượngErr x =newErr();// Tác động vào đối tượng x.input("Error 2001","- Lỗi này tạm thời chưa có nội dung"); x.output();}
- Đối tượng (Object): trong lập trình hướng đối tượng, một thực thể được coi là đối tượng khi nó có các thuộc tính và các hành vi.
Ví dụ 4:// Định nghĩa lớp đối tượng PersonpublicclassPerson{// khai báo một vài thuộc tính (attributes)privateString name;protectedString age;double height;// Khai báo các hành vi (methods)publicvoidmoving(){// di chuyển}publicvoideating(){//ăn}publicvoiddrinking(){// uống}publicvoidsleeping(){//ngủ}//...}// Hàm mainpublicstaticvoidmain(String args[]){// Khởi tạo một đối tượng thuộc lớp PersonPerson x =newPerson();// ở đây x chính là 1 đối tượng, có đầy đủ các thuộc tính và hành vi trong lớp Person.}
3. Các phạm vi truy cập trong Java
-
OOP Java gồm 4 phạm vi truy cập cho lớp, thuộc tính, phương thức, gồm: private, protected, default, public.
-
Phạm vi private: chỉ cho phép truy cập nội bộ trong class. Tại ví dụ 4, ta thấy rằng, thuộc tính name của class Person để phạm vi truy cập là private, điều này có nghĩa là thuộc tính đó của class Person chỉ truy cập được đến trong class Person mà thôi.
-
Phạm vi protected: là một loại phạm vi cho phép truy cập được từ trong hay cả ngoài package (gói), nếu là ngoài package thì phải thông qua tính kế thừa (inheritance). Cả phạm vi private và protected đều chỉ áp dụng bên trong class như thuộc tính, phương thức, … ( đoạn này dựa trên thực hành nên em không chắc lắm ^^) . Không thể áp dụng cho phạm vi truy cập của lớp hoặc interface. Ví dụ nho nhỏ cho protected.
// Định nghĩa lớp X trong gói apackagea;publicclassX{protectedint x1, x2;protectedintplus(){return x1 + x2;}}// Định nghĩa lớp Y trong gói apackagea;publicclassY{publicstaticmain(String args[]){X c =newX(); c.x1 =1; c.x2 =2;System.out.print(c.plus());// Ta có thể thấy rằng chúng ta hoàn toàn truy xuất được đến các thuộc tính hay phương thức có trong X}}// Định nghĩa lớp Z trong gói bpackageb;publicclassZextendsa.X{publicstaticmain(String args[]){Z c =newX(); c.x1 =1; c.x2 =2;System.out.print(c.plus());// Khi này để truy xuất được đến các thuộc tính, phương thức trong X ta cần để Z kế thừa X.}}
-
Phạm vi default: là phạm vi mặc định, khi khai báo không cần ghi gì cả ( thuộc tính height trong ví dụ 4), đối với phạm vi default này, thì phạm vi truy cập cho phép chỉ trong cùng package (gói).
-
Phạm vi public: là phạm vi rộng nhất, bất cứ chỗ nào trong project đều có thể truy cập đến được. ( trong ví dụ 4, class Person để phạm vi truy cập là public, vì thế bất kỳ nơi nào trong project đều có thể gọi đến class Person).
4. Các tính chất trong OOP Java
-
OOP Java có 4 tính chất, gồm: tính trừu tượng (abstract), tính kế thừa (inheritance), tính đóng gói (encapsulation), tính đa hình (polymorphism).
-
Tính trừu tượng (abstract): abstract có nghĩa là chúng ta đi tổng quát hóa một cái gì đó mà không cần đi vào chi tiết quá vào nó, nhưng người nghe vẫn hiểu được nó là cái gì. Trong OOP thì tính trừu tượng tức là ta đi lựa chọn các thuộc tính và các phương thức cần thiết của đối tượng để giải quyết bài toán. Bởi trong thực tế, một đối tượng có thể có rất nhiều thuộc tính và phương thức, nhưng không liên quan và không cần sử dụng trong bài toán đề ra.
Ví dụ 5: trong bài toán quản lý mèo, chẳng hạn đối tượng mèo chúng ta chỉ cần khái quát nó thành 1 lớp kiểu:publicclass cat{// Các thuộc tínhprivateint ID;privateString species;// chủng loạiprivateString origin;// Xuất xứprivatedouble weight;// cân nặng// Các phương thứcpublicvoidinput(){}publicvoidoutput(){}}
Chúng ta không cần thiết phải nhảy vào chi tiết thuộc tính kiểu: số lông, số chân, số ngón chân trên mỗi bàn chân, số tai, số mắt, … hay các phương thức kiểu: ăn, di chuyển, … Nhưng người nghe vẫn hiểu được nó là con mèo là đủ và quan trọng hơn, các thuộc tính phương thức mà chúng ta tạo ra đều có thể được sử dụng đến để giải quyết bài toán quản lý mèo.
-
Tính kế thừa (inheritance): Chỉ đơn giản là chúng ta tái sử dụng lại các thuộc tính, phương thức ở class khác mà không cần phải xây dựng lại từ đầu.
Ví dụ 6:// Định nghĩa lớp TaiKhoanpublicclassTaiKhoan{protectedString ID;protectedString name;protectedString userName;protectedString passWord;protectedvoidinput(){// Triển khai nhập dữ liệu}protectedvoidoutput(){// Xuất dữ liệu}}// Định nghĩa lớp tài khoản giáo viên kế thừa lớp tài khoảnpublicclassTKGiaoVienextendsTaiKhoan{privateString specialized;// Chuyên ngành privateString qualification;// trình độ chuyên môn// Tái sử dụng phương thức đã có sẵn trong class TaiKhoan@Overridepublicvoidinput(){super.input();// Triển khai tiếp nhập dữ liệu cho các thuộc tính trong class TKGiaoVien}@Overridepublicvoidoutput(){super.ouput();// Triển khai tiếp xuất dữ liệu cho các thuộc tính trong class TKGiaoVien}}// Định nghĩa tiếp lớp tài quản trị viên kế thừa lớp tài khoản cho thấy sức mạnh kế thừapublicclass TKQTV extendsTaiKhoan{privateString permission;// Tái sử dụng phương thức đã có sẵn trong class TaiKhoan@Overridepublicvoidinput(){super.input();// Triển khai tiếp nhập dữ liệu cho các thuộc tính trong class TKQTV}@Overridepublicvoidoutput(){super.ouput();// Triển khai tiếp xuất dữ liệu cho các thuộc tính trong class TKQTV}}
Qua ví dụ trên chúng ta có thể thấy 2 lớp đối tượng TKGiaoVien và TKQTV không cần phải xây dựng lại từ đầu nhưng vẫn chứa đầy đủ các thuộc tính cũng như phương thức cần thiết nhờ vào tính kế thừa.
-
Tính đóng gói (encapsulation): đóng gói ở đây có nghĩa là đóng gói attributes, methods thành class, đóng gói các class thành package, … Nhằm che giấu thông tin và đảm bảo sự toàn vẹn của dữ liệu.
Ví dụ 7:// Định nghĩa lớp MoneypublicclassMoney{/* Toàn bộ các thuộc tính để phạm vi truy cập là private, điều này có nghĩa là các thuộc tính này không thể truy cập được bởi các lớp bên ngoài*/privateString donVi;privateString menhGia;privateString seri;// Khi này để tương tác với các thuộc tính trên, chúng ta sử dụng các hàm setter, getter,publicStringgetDonVi(){return donVi;}publicvoidsetDonVi(String donVi){this.donVi = donVi;}publicStringgetMenhGia(){return menhGia;}publicvoidsetMenhGia(String menhGia){this.menhGia = menhGia;}publicStringgetSeri(){return seri;}publicvoidsetSeri(String seri){this.seri = seri;}}
Một vài lợi ích nữa trong việc đóng gói là:
- Chúng ta có thể kiểm soát chỉ đọc hoặc chỉ ghi, hoặc cả ghi cả đọc cho các thuộc tính, tức là chỉ có setters hoặc getters, hoặc có cả setters, getters.
- Người sử dụng của class không biết được cách các class lưu trữ dữ liệu hay được gọi là sự kiểm soát dữ liệu.
- Một class có thể thay đổi kiểu dữ liệu của một thuộc tính và người dùng class không cần sự thay đổi trong code ??? (lợi ích này em sưu tầm được nhưng đọc không hiểu gì và nghe rất vi diệu, mong anh đọc đến đây có thể cho em giải đáp kỹ chỗ này, em cảm ơn)
-
Tính đa hình (polymorphism): chỉ sự đa hình thái, chẳng hạn cùng có một phương thức giống nhau nhưng tùy vào tham số truyền vào hay sự cài đặt của lớp con mà nó thực hiện các công việc khác nhau. Tính đa hình liên quan tới 2 khái niệm là: overriding (ghi đè) và overloading (nạp chồng).
- overriding (ghi đè) là đi viết lại, định nghĩa lại phương thức mà nó kế thừa từ lớp cha.
Ví dụ 8:
// Định nghĩa lớp AnimalpublicclassAnimal{publicvoidoutput(){System.out.println("- Đây là lớp động vật.");}}// Định nghĩa lớp Cat kế thừa lớp AnimalpublicclassCat{/* Class Cat kế thừa phương thức output() từ lớp Animal, nhưng phương thức output() trong lớp Cat lại khác so với phương thức output() trong Animal, ta gọi nó là overriding (ghi đè).*/@Overridepublicvoidoutput(){System.out.println("- Đây là lớp mòe :D.");}}
- overloading (nạp chồng) sử dụng các phương thức có cùng tên nhưng tham số đầu vào lại khác nhau.
Ví dụ 9:
// Định nghĩa lớp AnimalpublicclassAnimal{// tạo các phương thức cùng tên nhưng các tham số đầu vào khác nhaupublicvoidoutput(){System.out.println("- Đây là lớp động vật ăn thịt.");}publicvoidoutput(int i){System.out.println("- Đây là lớp động vật ăn cỏ.");}publicvoidoutput(int i,int j){System.out.println("- Đây là lớp động vật ăn chay???");}}// triển khai trong hàm mainpublicstaticvoidmain(String args[]){Animal x =newAnimal(); x.output();// kết quả: - Đây là lớp động vật ăn thịt. x.output(1);// kết quả: - Đây là lớp động vật ăn cỏ. x.output(1,2);// kết quả: - Đây là lớp động vật ăn chay???.}
- overriding (ghi đè) là đi viết lại, định nghĩa lại phương thức mà nó kế thừa từ lớp cha.
5. Ưu điểm, nhược điểm
5.1. Ưu điểm
- Nâng cao hiệu năng phát triển phần mềm, liên quan tới 3 yếu tố trong OOP:
- Tính Mô – đun: 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 các đối tượng cụ thể, hay mỗi đối tượng có một nhiệm vụ riêng.
- Tính mở rộng: Các đối tượng có thể mở rộng thêm các thuộc tính mới, các hành vi mới trong tương lai.
- Tính tái sử dụng: Các đối tượng có thể tái sử dụng một ứng dụng hoặc nhiều ứng dụng khác nhau.
Nhờ vào các yếu tố trên mà OOP giúp tăng hiệu năng phát triển phần mềm so với lập trình hướng thủ tục truyền thống.
- Nâng cao khả năng bảo trì phần mềm: Chính nhờ các yếu tố kể trên mà việc bảo trì cũng trở nên dễ dàng hơn, vì thiết kế theo mô-đun nên việc thay đổi một phần của chương trình có thể không làm ảnh hưởng đến những phần còn lại, rất phù hợp với những dự án lớn, đòi việc phải bảo trì và thay đổi nhiều.
- Phát triển phần mềm nhanh hơn: Nhờ vào tính tái sử dụng mà các phần mềm được phát triển nhanh hơn, OOP thường có thư viện đối tượng phong phú, hay những đối tượng do chính bạn tự định nghĩa, các đoạn code được tối ưu hóa đều có thể được tái sử dụng trong tương lai. => giảm thiểu chi phí phát triển.
5.2. Nhược điểm - Khá phức tạp, có thể khó nhằn cho beginner, bởi nó đòi hỏi sự tư duy dựa trên sự tương tác giữa các đối tượng, do đó chúng ta cần nắm được bản chất: lớp, đối tượng, thuộc tính, phương thức; nắm được 4 tính chất của hướng đối tượng gồm: tính trừu tượng (abstract), tính kế thừa (inheritance), tính đóng gói (encapsulation), tính đa hình (polymorphism).
- Chương trình có thể chậm và kích thước lớn hơn so với các chương trình lập trình hướng thủ tục. Do các phần mềm này thường yêu cầu nhiều câu lệnh hơn để thực thi, người lập trình cần viết ra nhiều dòng mã hơn để đảm bảo các thuộc tính, phương thức của đối tượng => kích thước chương trình lớn theo.
- Lập trình hướng đối tượng không phải là chìa khóa vạn năng cho nhiều vấn đề. Theo em, mỗi một phương pháp lập trình đều có sự phù hợp với mỗi bài toán thực tế nhất định. Chẳng hạn giải phương trình bậc 2, thay vì phải ngồi viết ra đối tượng phương trình bậc 2 (theo OOP), cài đặt các thuộc tính và các phương thức cho nó, trong lập trình hướng chức năng trong 1 file duy nhất, ta chỉ cần viết mỗi một hàm con có chức năng tìm nghiệm nhờ vào việc truyền vào 3 tham số giá trị và cho in nghiệm là xong.
6. Kết thúc
- Đây là toàn bộ sự hiểu biết, cũng như trong quá trình viết lên đây em cũng đã tìm hiểu lại những kiến thức mà mình không được đụng đến trong quá trình học tập. Hi vọng anh có thể đọc và đưa ra ý kiến về bài viết của em, phần nào ổn, phần nào chưa được mong anh chỉ rõ để em tìm hiểu lại. Em xin chân thành cảm ơn.
Nguồn: viblo.asia