Lập trình hướng đối tượng (tiếng Anh: Object-oriented programming, viết tắt: OOP) là một kỹ thuật lập trình được sử dụng phổ biến nhất hiện nay. OOP còn được xem là một cách viết code tiêu chuẩn của hầu hết các lập trình viên.
Ưu điểm của lập trình hướng đối tượng (OOP)
- OOP giúp chương trình chạy nhanh hơn và dễ thực thi hơn
- OOP cung cấp một cấu trúc hệ thống rõ ràng
- OOP giúp code tuân theo nguyên lý DRY “Don’t Repeat Yourself”. Do đó việc bảo trì, chỉnh sửa và debug code trở nên dễ dàng hơn
- OOP tăng khả năng tái sử dụng code, vì vậy chương trình sẽ ít code hơn và kéo theo vòng đời phát triển phần mềm ngắn hơn.
Tip: Nguyên lý “Don’t Repeat Yourself” (DRY) giúp giảm việc lặp lại code. Chúng ta nên tách những đoạn code có chung logic, đặt chúng vào chung một nơi để có thể tái sử dụng thay vì viết lại đoạn code tương tự.
1. Class và Object là gì?
Class (Lớp) và object (đối tượng) là hai khái niệm chính trong lập trình hướng đối tượng.
Hãy nhìn vào ví dụ bên dưới để thấy sự khác nhau giữa class và object:
Một ví dụ khác:
Ta có thể coi class như là một template (khuôn mẫu) cho nhiều object, và một object như là một instance (thực thể) của class.
Khi một object được tạo ra, nó kế thừa tất cả variable (biến số) và method (phương thức) của class tương ứng.
1.1 Khởi tạo Class và Object
Tạo một class Car
với variable x
:
public class Car { int x = 5; }
Khởi tạo một object có tên là audi
và in ra giá trị x
:
public class Main { public static void main(String[] args) { Car audi = new Car(); System.out.println(audi.x); } }
Khởi tạo hai object từ class Car
:
public class Main { public static void main(String[] args) { Car audi = new Car(); // Object 1 Car vinfast = new Car(); // Object 2 System.out.println(audi.x); System.out.println(vinfast.x); } }
1.2 Class Attribute
Ở những ví dụ trước đó, chúng ta sử dụng định nghĩa variable (biến số) để gọi x. Bạn có thể gọi x là attribute (thuộc tính) của class. Hoặc bạn cũng có thể nói attribute là variable bên trong class.
Khởi tạo một class Car
có hai attribute x
và y
:
public class Car { int x = 5; int y = 3; }
field cũng là một tên gọi khác của attribute
Bạn có thể truy cập attribute thông qua việc khởi tạo object
public class Main { public static void main(String[] args) { Car audi = new Car(); System.out.println(audi.x); } }
Bạn cũng có thể chỉnh sửa giá trị của attribute:
public class Main { public static void main(String[] args) { Car audi = new Car(); audi.x = 40; // gán giá trị x = 40 System.out.println(audi.x); } }
Nếu bạn tạo ra nhiều object từ một class, bạn có thể thay đổi giá trị của attribute trong một object bất kỳ mà không làm thay đổi giá trị của attribute trong các object còn lại.
Ví dụ, khi gán giá trị của x
trong audi
bằng 25
thì giá trị của x
trong vinfast
không thay đổi:
public class Car { int x = 5; int y = 3; } public class Main { public static void main(String[] args) { Car audi = new Car(); // Object 1 Car vinfast = new Car(); // Object 2 audi.x = 25; System.out.println(audi.x); // Kết quả 25 System.out.println(vinfast.x); // Kết quả 5 } }
1.3 Class Method
Method (phương thức) được khai báo bên trong class, method được dùng để mô tả một hành động cụ thể.
Tạo một method myMethod
trong Car
:
public class Car { public void myMethod() { System.out.println("Hello World!"); } }
myMethod()
in ra đoạn text Hello World
khi nó được gọi. Bên dưới là ví dụ gọi một method:
public class Main { public static void main(String[] args) { Car audi = new Car(); audi.myMethod(); // Kết quả là "Hello World" } }
1.4 Constructor
Constructor là một method đặc biệt được dùng để khởi tạo object. Constructor được thực thi khi một object được tạo ra. Constructor còn được dùng để thiết lập giá trị ban đầu cho các attribute của object:
public class Car { int x; // Tạo constructor public Car() { x = 5; // Thiết lập giá trị ban đầu cho attribute x } } public class Main { public static void main(String[] args) { Car audi = new Car(); // Constructor được thực thi System.out.println(audi.x); // In ra giá trị của x là 5 } }
Lưu ý rằng constructor phải trùng với tên class, và không có return type (ví dụ như là
void
).Cũng lưu ý rằng constructor được thực thi khi khởi tạo object.
Tất cả class điều có default constructor: Nếu bạn không tạo constructor bên trong class, thì class sẽ dùng default constructor. Tuy nhiên, sau đó bạn không thể thiết lập giá trị mặc định cho các attribute trong class.
Constructors có thể chứa các parameters (tham số), những parameters này được dùng để khởi tạo giá trị ban đầu cho các attribute.
Theo ví dụ bên dưới, constructor có parameter int y
. Bên trong constructor, chúng ta khởi tạo giá trị của x
bằng y
(x=y
). Khi chúng ta gọi constructor, chúng ta truyền một parameter (5
) và x
sẽ được gán giá trị bằng 5
:
public class Car { int x; public Car(int y) { x = y; } } public class Main { public static void main(String[] args) { Car audi = new Car(5); System.out.println(audi.x); // Kết quả: 5 } }
1.5 Modifiers
Có lẽ bạn đã khá quen thuộc với từ khoá public
, từ khoá này xuất hiện hầu hết trong tất cả các ví dụ của chúng ta:
Từ khoá public
là một access modifier, nghĩa là nó được sử dụng để thiết lập mức độ truy cập cho class, attribute, method và constructor.
Chúng ta chia modifier thành hai nhóm:
- Access Modifiers – kiểm soát mức độ truy cập
- Non-Access Modifiers – không kiểm soát mức độ truy cập, nhưng có chức năng khác
Access Modifiers
Đối với class, bạn có thể dùng các modifiers như public
hoặc default:
public
: Class có thể được truy cập bởi các class khác.- default: Class chỉ được truy cập bởi các class cùng chung package (Định nghĩa này chỉ đúng đối với Java, tùy vào mỗi ngôn ngữ khác nhau thì sẽ có các định nghĩa khác nhau). Điều này được áp dụng khi bạn không chỉ định một modifier.
Đối với attribute, method và constructor, bạn có thể dùng một trong các modifiers bên dưới:
public
: Code được truy cập bởi tất cả các class.private
: Code chỉ được truy cập bên trong class.- default: Code chỉ được truy cập khi cùng một package (Định nghĩa này chỉ đúng đối với Java, tùy vào mỗi ngôn ngữ khác nhau thì sẽ có các định nghĩa khác nhau). Điều này được áp dụng khi bạn không chỉ định một modifier.
protected
: Code chỉ được truy cập khi cùng một package và subclass (Định nghĩa subclass sẽ được mô tả ở nội dung bên dưới).
Non-Access Modifiers
Đối với class, bạn có thể dùng các modifiers như final
hoặc abstract
:
final
: Class không thể được kế thừa bởi các class khác.abstract
: Class không được dùng để tạo object (Định nghĩa abstract class sẽ được mô tả ở nội dung bên dưới). Để sử dụng abstract class, nó phải được kế thừa từ class khác.
Đối với attributes và methods, bạn có thể dùng một trong các modifiers bên dưới:
final
: Attribute và method không thể được overridden(ghi đè) hoặc chỉnh sửa.static
: Attribute và method thuộc về class, chứ không phải thuộc về object.abstract
: Chỉ được sử dụng bên trong abstract class và các method bên trong abstract class. Abstract method không có body, ví dụ abstract void run();. Body của abstract method chỉ được định nghĩa bởi subclass sau khi kế thừa (Định nghĩa kế thừa sẽ được mô tả ở nội dung bên dưới).
2. Bốn tính chất của lập trình hướng đối tượng
2.1 Encapsulation (Tính đóng gói)
Encapsulation đảm bảo dữ liệu nhạy cảm bị ẩn đi từ phía người dùng. Để thực hiện điều này, bạn phải:
- Khai báo
private
cho các variable/attribute. - Khai báo
public
cho các get và set method để truy cập và chỉnh sửa giá trị của cácprivate
variable/attribute.
Get và Set
Ở nội dung trước, bạn đã biết rằng private
attribute chỉ có thể được truy cập bên trong class. Tuy nhiên, chúng ta có thể truy cập bằng cách khai báo get và set method.
get
method trả về giá trị của attribute, và set
method dùng để gán giá trị cho attribute.
public class Person { private String name; // private = restricted access // Getter public String getName() { return name; } // Setter public void setName(String newName) { this.name = newName; } }
Lợi ích của Encapsulation
- Kiểm soát attribute và method tốt hơn.
- Linh động: lập trình viên có thể thay đổi một phần code mà không ảnh hưởng đến những phần code còn lại.
- Tăng tính bảo mật cho dữ liệu.
2.2 Inheritance (Tính kế thừa)
Có thể kế thừa toàn bộ attribute và method từ một class sang một class khác. Chúng ta chia khái niệm inheritance thành hai nhóm:
- subclass (class con) – là class kế thừa class khác.
- superclass (class cha) – là class được kế thừa.
Để kế thừa, chúng ta sử dụng từ khoá extends
(đối với Java).
class Vehicle { protected String brand = "Ford"; // Vehicle attribute public void honk() { // Vehicle method System.out.println("Tuut, tuut!"); } } class Car extends Vehicle { private String modelName = "Mustang"; // Car attribute } class Main { public static void main(String[] args) { // khởi tạo object myCar Car myCar = new Car(); // kết quả: Tuut, tuut! myCar.honk(); // kết quả: Ford Mustang System.out.println(myCar.brand + " " + myCar.modelName); } }
Nếu chúng ta set attribute brand trong Vehicle thành
private
, classCar
sẽ không thể truy cập nó.
Lợi ích của Inheritance
Tăng tính tái sử dụng code: sử dụng lại các attribute và method của class có sẵn khi bạn muốn tạo một class mới.
2.3 Polymorphism (Tính đa hình)
Như đã nói ở trên, Inheritance là kế thừa các attribute và method từ một class sang một class khác. Còn Polymorphism là sử dụng một method để thể hiện nhiều chức năng khác nhau.
Ví dụ, Animal
là superclass có method animalSound()
. Subclass của Animal
là Pig
, Dog
.
class Animal { public void animalSound() { System.out.println("The animal makes a sound"); } } class Pig extends Animal { public void animalSound() { System.out.println("The pig says: wee wee"); } } class Dog extends Animal { public void animalSound() { System.out.println("The dog says: bow wow"); } }
Bây giờ chúng ta sẽ tạo object Pig
và object Dog
, sau đó gọi method animalSound()
của 2 object:
class Main { public static void main(String[] args) { Animal myAnimal = new Animal(); Animal myPig = new Pig(); Animal myDog = new Dog(); myAnimal.animalSound(); // Kết quả: The animal makes a sound myPig.animalSound(); // Kết quả: The pig says: wee wee myDog.animalSound(); // Kết quả: The dog says: bow wow } }
2.4 Abstraction (Tính trừu tượng)
Abstraction là quá trình ẩn các chi tiết cụ thể và hiển thị những thông tin cần thiết đến người dùng.
Abstraction có thể được thực hiện thông qua abstract classe hoặc interface.
Từ khoá abstract
là một non-access modifier, được sử dụng cho class và method:
- Abstract class: là một class đặc biệt không thể được dùng để khởi tạo object (Để sử dụng được abstract class, nó phải được kế thừa từ một class khác).
- Abstract method: chỉ được sử dụng trong abstract class, và nó không có body. Body chỉ được khai báo trong subclass.
Trong một abstract class có thể có cả abstract method và các method thông thường khác.
abstract class Animal { public abstract void animalSound(); public void sleep() { System.out.println("Zzz"); } }
Ở ví dụ trên, chúng ta không thể khởi tạo một đối tượng từ class Animal
. Để sử dụng abstract class, nó phải được kế thừa từ một class khác.
// Abstract class abstract class Animal { public abstract void animalSound(); public void sleep() { System.out.println("Zzz"); } } class Pig extends Animal { public void animalSound() { System.out.println("The pig says: wee wee"); } } class Main { public static void main(String[] args) { Pig myPig = new Pig(); myPig.animalSound(); // Kết quả: The pig says: wee wee myPig.sleep(); // Kết quả: Zzz } }
Một cách khác để thực hiện abstraction là dùng interface.
// interface interface Animal { public void animalSound(); public void run(); } class Pig implements Animal { public void animalSound() { System.out.println("The pig says: wee wee"); } public void sleep() { System.out.println("Zzz"); } } class Main { public static void main(String[] args) { Pig myPig = new Pig(); myPig.animalSound(); // Kết quả: The pig says: wee wee myPig.sleep(); // Kết quả: Zzz } }
Những lưu ý khi sử dụng Interface:
- Như abstract class, interface không thể được dùng để khởi tạo object.
- Method trong interface không có body – body chỉ được định nghĩa trong class implement interface.
- Interface không có constructor.
Lợi ích khi sử dụng Interface
Sử dụng interface để thực hiện việc bảo mật – ẩn các chi tiết không cần thiết và chỉ hiển thị những chi tiết quan trọng của object.
3. Kết luận
Hi vọng sau bài viết này, các bạn sẽ biết rõ hơn về lập trình hướng đối tượng là gì và có thể áp dụng kỹ thuật này để xây dựng dự án của mình tối ưu và hiệu quả hơn hoặc củng cố kiến thức trước các buổi phỏng vấn.
Khóa Học Lập Trình Cơ Bản
Nếu bạn đang làm trái ngành và có dự định chuyển sang ngành lập trình.
Đây là Khóa Học Lập Trình Cơ Bản từ con số 0 kéo dài trong vòng 1 tháng, rất phù hợp với những bạn muốn kiểm chứng xem mình có phù hợp với nghề lập trình hay không.