OOP - Tính Đa hình và Tính Trừu tượng
Chào mừng bạn đã quay trở lại series "Chinh Phục Java"! Ở bài trước, chúng ta đã tìm hiểu về Tính đóng gói và Tính kế thừa. Hôm nay, chúng ta sẽ hoàn thiện kiến thức về Lập trình Hướng đối tượng (OOP). Chúng ta sẽ khám phá hai trụ cột cuối cùng. Đó là **Tính đa hình (Polymorphism)** và **Tính trừu tượng (Abstraction)**. Đây là những khái niệm giúp code của bạn trở nên cực kỳ linh hoạt và mạnh mẽ.
1. Tính Đa hình (Polymorphism) - Một hành động, nhiều cách thể hiện
Từ "Polymorphism" có nghĩa là "nhiều hình thái". Trong OOP, tính đa hình cho phép một hành động có thể được thực hiện theo nhiều cách khác nhau. Hãy tưởng tượng hành động "phát ra tiếng kêu" của các loài động vật. Một con chó sẽ sủa, một con mèo sẽ kêu meo meo, và một con vịt sẽ kêu cạc cạc. Hành động thì giống nhau, nhưng cách thực hiện lại khác nhau tùy vào từng đối tượng.
Trong Java, tính đa hình thường được thể hiện qua **Ghi đè phương thức (Method Overriding)**. Điều này xảy ra khi một lớp con cung cấp một định nghĩa riêng cho một phương thức đã tồn tại ở lớp cha của nó. Lớp con sẽ "ghi đè" lên hành vi của lớp cha. Chúng ta sử dụng annotation @Override để chỉ rõ rằng chúng ta đang cố tình làm điều này.
Hãy xem ví dụ sau:
// File: Animal.java (Lớp cha)
public class Animal {
public void makeSound() {
System.out.println("Động vật đang phát ra tiếng kêu...");
}
}
// File: Dog.java (Lớp con)
public class Dog extends Animal {
@Override // Ghi đè phương thức của lớp cha
public void makeSound() {
System.out.println("Chó sủa: Gâu gâu!");
}
}
// File: Cat.java (Lớp con)
public class Cat extends Animal {
@Override // Ghi đè phương thức của lớp cha
public void makeSound() {
System.out.println("Mèo kêu: Meo meo!");
}
}
// File: Main.java
public class Main {
public static void main(String[] args) {
Animal myAnimal = new Animal();
Animal myDog = new Dog(); // Một đối tượng Dog cũng LÀ một Animal
Animal myCat = new Cat(); // Một đối tượng Cat cũng LÀ một Animal
myAnimal.makeSound(); // In ra: Động vật đang phát ra tiếng kêu...
myDog.makeSound(); // In ra: Chó sủa: Gâu gâu!
myCat.makeSound(); // In ra: Mèo kêu: Meo meo!
}
}
Điều kỳ diệu ở đây là: mặc dù `myDog` và `myCat` đều được khai báo với kiểu `Animal`, nhưng khi gọi phương thức `makeSound()`, Java đủ thông minh để biết phải chạy phiên bản đã được ghi đè của lớp `Dog` và `Cat`. Đây chính là sức mạnh của tính đa hình.
2. Tính Trừu tượng (Abstraction) - Che giấu sự phức tạp
Hãy nghĩ về việc bạn lái một chiếc xe hơi. Bạn chỉ cần biết về vô lăng, chân ga, chân phanh. Bạn không cần phải biết piston di chuyển như thế nào hay nhiên liệu được đốt ra sao. Sự phức tạp đó đã được "trừu tượng hóa". **Tính trừu tượng** trong OOP có cùng mục đích. Nó che giấu các chi tiết triển khai phức tạp. Nó chỉ hiển thị các chức năng cần thiết cho người dùng.
Tính trừu tượng giúp chúng ta tập trung vào "cái gì" (what) thay vì "như thế nào" (how). Trong Java, chúng ta đạt được tính trừu tượng thông qua hai công cụ chính: **Lớp trừu tượng (Abstract Class)** và **Giao diện (Interface)**.
2.1. Lớp trừu tượng (Abstract Class)
Một lớp trừu tượng là một lớp "chưa hoàn chỉnh". Nó không thể được dùng để tạo ra đối tượng. Nó hoạt động như một lớp cha cơ sở cho các lớp con khác. Lớp trừu tượng có thể chứa các phương thức trừu tượng. Một phương thức trừu tượng chỉ có phần khai báo, không có phần thân (code). Các lớp con kế thừa từ lớp trừu tượng **bắt buộc** phải cung cấp định nghĩa cho các phương thức trừu tượng đó.
// Một lớp trừu tượng
abstract class Shape {
// Một phương thức thông thường
public void display() {
System.out.println("Đây là một hình.");
}
// Một phương thức trừu tượng - không có phần thân
public abstract double calculateArea();
}
// Lớp con phải định nghĩa phương thức trừu tượng
class Circle extends Shape {
double radius = 5.0;
@Override
public double calculateArea() {
return Math.PI * radius * radius;
}
}
2.2. Giao diện (Interface)
Một Interface còn trừu tượng hơn cả một Abstract Class. Nó giống như một "bản hợp đồng". Nó chỉ định nghĩa các hành vi (phương thức) mà một lớp phải thực hiện, nhưng không nói gì về cách thực hiện. Tất cả các phương thức trong một Interface (ở các phiên bản Java cũ) đều là trừu tượng. Một lớp có thể **implement (thực thi)** một hoặc nhiều Interface.
Interface rất mạnh mẽ trong việc định nghĩa các "vai trò" hoặc "khả năng". Ví dụ, chúng ta có thể tạo một interface `CanFly` (Có thể bay). Các lớp như `Bird` và `Airplane` đều có thể implement interface này, dù chúng hoàn toàn khác nhau.
// Một interface
interface Drivable {
void drive(); // Mặc định là public và abstract
void stop();
}
// Một lớp thực thi interface
class Car implements Drivable {
@Override
public void drive() {
System.out.println("Xe hơi đang chạy...");
}
@Override
public void stop() {
System.out.println("Xe hơi đã dừng.");
}
}
Kết luận
Chúc mừng bạn đã hoàn thành việc tìm hiểu bốn trụ cột của OOP! Tính đa hình cho phép code của bạn linh hoạt hơn. Tính trừu tượng giúp bạn quản lý sự phức tạp. Việc kết hợp cả bốn nguyên tắc: Đóng gói, Kế thừa, Đa hình và Trừu tượng, sẽ giúp bạn viết ra những chương trình Java mạnh mẽ, dễ bảo trì và dễ mở rộng. Ở bài tiếp theo, chúng ta sẽ khám phá về Collections Framework - bộ công cụ mạnh mẽ để làm việc với các tập hợp dữ liệu.
0 Bình luận
Vui lòng đăng nhập để gửi bình luận.