Tính Trừu Tượng trong Java 🎯
🎯 Mục tiêu: Học cách sử dụng tính trừu tượng để ẩn chi tiết triển khai và chỉ hiển thị các tính năng cần thiết trong Java.
Giới thiệu 📝
Tính trừu tượng (Abstraction) là một trong những nguyên tắc cơ bản của lập trình hướng đối tượng. Nó giúp ẩn các chi tiết triển khai phức tạp và chỉ hiển thị các tính năng cần thiết cho người dùng.
💡 Fun Fact: Trong Java, tính trừu tượng được thể hiện thông qua abstract class và interface, giúp code dễ bảo trì và mở rộng hơn.
1. Cú Pháp Cơ Bản ⚡
Abstract Class
public abstract class Shape {
protected String color;
protected boolean filled;
public Shape(String color, boolean filled) {
this.color = color;
this.filled = filled;
}
// Phương thức abstract
public abstract double getArea();
public abstract double getPerimeter();
// Phương thức thông thường
public void displayInfo() {
System.out.printf("Hình: %s, Màu: %s, Đã tô: %b%n",
getClass().getSimpleName(), color, filled);
}
}
public class Circle extends Shape {
private double radius;
public Circle(String color, boolean filled, double radius) {
super(color, filled);
this.radius = radius;
}
@Override
public double getArea() {
return Math.PI * radius * radius;
}
@Override
public double getPerimeter() {
return 2 * Math.PI * radius;
}
}
Interface
public interface Drawable {
void draw();
void erase();
void resize(double scale);
}
public class Circle implements Drawable {
private double radius;
public Circle(double radius) {
this.radius = radius;
}
@Override
public void draw() {
System.out.println("Vẽ hình tròn với bán kính: " + radius);
}
@Override
public void erase() {
System.out.println("Xóa hình tròn");
}
@Override
public void resize(double scale) {
radius *= scale;
System.out.println("Thay đổi kích thước hình tròn. Bán kính mới: " + radius);
}
}
2. Các Loại Trừu Tượng 🔄
Trừu Tượng Với Abstract Class
public abstract class Animal {
protected String name;
protected int age;
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public abstract void makeSound();
public abstract void move();
public void displayInfo() {
System.out.printf("Động vật: %s, Tuổi: %d%n", name, age);
}
}
public class Dog extends Animal {
private String breed;
public Dog(String name, int age, String breed) {
super(name, age);
this.breed = breed;
}
@Override
public void makeSound() {
System.out.println("Gâu gâu!");
}
@Override
public void move() {
System.out.println("Chạy bằng 4 chân");
}
}
Trừu Tượng Với Interface
public interface PaymentMethod {
boolean processPayment(double amount);
void refund(double amount);
String getPaymentDetails();
}
public class CreditCard implements PaymentMethod {
private String cardNumber;
private String expiryDate;
public CreditCard(String cardNumber, String expiryDate) {
this.cardNumber = cardNumber;
this.expiryDate = expiryDate;
}
@Override
public boolean processPayment(double amount) {
System.out.printf("Xử lý thanh toán %.2f bằng thẻ tín dụng%n", amount);
return true;
}
@Override
public void refund(double amount) {
System.out.printf("Hoàn tiền %.2f vào thẻ tín dụng%n", amount);
}
@Override
public String getPaymentDetails() {
return "Thẻ tín dụng: " + cardNumber + ", Hạn sử dụng: " + expiryDate;
}
}
public class PayPal implements PaymentMethod {
private String email;
public PayPal(String email) {
this.email = email;
}
@Override
public boolean processPayment(double amount) {
System.out.printf("Xử lý thanh toán %.2f bằng PayPal%n", amount);
return true;
}
@Override
public void refund(double amount) {
System.out.printf("Hoàn tiền %.2f vào tài khoản PayPal%n", amount);
}
@Override
public String getPaymentDetails() {
return "PayPal: " + email;
}
}
3. Ví Dụ Thực Tế 🚀
Quản Lý Phương Tiện
public abstract class Vehicle {
protected String brand;
protected String model;
protected int year;
public Vehicle(String brand, String model, int year) {
this.brand = brand;
this.model = model;
this.year = year;
}
public abstract void start();
public abstract void stop();
public abstract void accelerate();
public abstract void brake();
public void displayInfo() {
System.out.printf("Phương tiện: %s %s %d%n", brand, model, year);
}
}
public class Car extends Vehicle {
private int numberOfDoors;
private String transmissionType;
public Car(String brand, String model, int year, int numberOfDoors, String transmissionType) {
super(brand, model, year);
this.numberOfDoors = numberOfDoors;
this.transmissionType = transmissionType;
}
@Override
public void start() {
System.out.println("Vặn chìa khóa xe");
System.out.println("Đạp phanh");
System.out.println("Khởi động động cơ");
}
@Override
public void stop() {
System.out.println("Đạp phanh");
System.out.println("Tắt động cơ");
}
@Override
public void accelerate() {
System.out.println("Đạp ga");
System.out.println("Tăng tốc");
}
@Override
public void brake() {
System.out.println("Đạp phanh");
System.out.println("Giảm tốc");
}
@Override
public void displayInfo() {
super.displayInfo();
System.out.printf("Số cửa: %d, Hộp số: %s%n", numberOfDoors, transmissionType);
}
}
public class Motorcycle extends Vehicle {
private boolean hasSidecar;
private String engineType;
public Motorcycle(String brand, String model, int year, boolean hasSidecar, String engineType) {
super(brand, model, year);
this.hasSidecar = hasSidecar;
this.engineType = engineType;
}
@Override
public void start() {
System.out.println("Đạp cần khởi động");
System.out.println("Bật công tắc điện");
System.out.println("Khởi động động cơ");
}
@Override
public void stop() {
System.out.println("Đạp phanh");
System.out.println("Tắt động cơ");
}
@Override
public void accelerate() {
System.out.println("Vặn tay ga");
System.out.println("Tăng tốc");
}
@Override
public void brake() {
System.out.println("Đạp phanh");
System.out.println("Giảm tốc");
}
@Override
public void displayInfo() {
super.displayInfo();
System.out.printf("Có bánh phụ: %b, Loại động cơ: %s%n", hasSidecar, engineType);
}
}
Quản Lý Hình Học
public interface GeometricShape {
double getArea();
double getPerimeter();
void draw();
void resize(double scale);
}
public abstract class Shape implements GeometricShape {
protected String color;
protected boolean filled;
public Shape(String color, boolean filled) {
this.color = color;
this.filled = filled;
}
@Override
public abstract double getArea();
@Override
public abstract double getPerimeter();
@Override
public void draw() {
System.out.printf("Vẽ hình %s với màu %s%n", getClass().getSimpleName(), color);
}
@Override
public abstract void resize(double scale);
public void displayInfo() {
System.out.printf("Hình: %s, Màu: %s, Đã tô: %b%n",
getClass().getSimpleName(), color, filled);
System.out.printf("Diện tích: %.2f, Chu vi: %.2f%n",
getArea(), getPerimeter());
}
}
public class Circle extends Shape {
private double radius;
public Circle(String color, boolean filled, double radius) {
super(color, filled);
this.radius = radius;
}
@Override
public double getArea() {
return Math.PI * radius * radius;
}
@Override
public double getPerimeter() {
return 2 * Math.PI * radius;
}
@Override
public void resize(double scale) {
radius *= scale;
System.out.printf("Thay đổi kích thước hình tròn. Bán kính mới: %.2f%n", radius);
}
@Override
public void displayInfo() {
super.displayInfo();
System.out.printf("Bán kính: %.2f%n", radius);
}
}
public class Rectangle extends Shape {
private double length;
private double width;
public Rectangle(String color, boolean filled, double length, double width) {
super(color, filled);
this.length = length;
this.width = width;
}
@Override
public double getArea() {
return length * width;
}
@Override
public double getPerimeter() {
return 2 * (length + width);
}
@Override
public void resize(double scale) {
length *= scale;
width *= scale;
System.out.printf("Thay đổi kích thước hình chữ nhật. Chiều dài: %.2f, Chiều rộng: %.2f%n",
length, width);
}
@Override
public void displayInfo() {
super.displayInfo();
System.out.printf("Chiều dài: %.2f, Chiều rộng: %.2f%n", length, width);
}
}
4. Best Practices ✅
-
Sử Dụng Abstract Class Cho Các Lớp Có Mối Quan Hệ "Is-A"
// Không nên
public interface Animal { }
// Nên
public abstract class Animal {
protected String name;
protected int age;
} -
Sử Dụng Interface Cho Các Hành Vi Chung
// Không nên
public abstract class PaymentMethod {
public abstract void processPayment();
}
// Nên
public interface PaymentMethod {
void processPayment();
void refund();
} -
Kết Hợp Interface Và Abstract Class
public interface Drawable {
void draw();
void erase();
}
public abstract class Shape implements Drawable {
protected String color;
protected boolean filled;
public abstract double getArea();
public abstract double getPerimeter();
}
5. Lỗi Thường Gặp ⚠️
-
Quên Triển Khai Phương Thức Abstract
// Lỗi
public class Circle extends Shape {
// Quên triển khai getArea() và getPerimeter()
}
// Đúng
public class Circle extends Shape {
@Override
public double getArea() {
return Math.PI * radius * radius;
}
@Override
public double getPerimeter() {
return 2 * Math.PI * radius;
}
} -
Tạo Đối Tượng Từ Abstract Class
// Lỗi
Shape shape = new Shape("red", true); // Không thể tạo đối tượng từ abstract class
// Đúng
Shape shape = new Circle("red", true, 5.0); -
Quên Triển Khai Tất Cả Phương Thức Của Interface
// Lỗi
public class Circle implements Drawable {
@Override
public void draw() { }
// Quên triển khai erase()
}
// Đúng
public class Circle implements Drawable {
@Override
public void draw() { }
@Override
public void erase() { }
}
💡 Lời khuyên: Hãy thực hành với các ví dụ thực tế để hiểu rõ hơn về cách sử dụng tính trừu tượng trong các tình huống khác nhau.
Tiếp Theo 🎯
Trong các bài học tiếp theo, chúng ta sẽ:
- Tìm hiểu về package và import
- Học cách sử dụng xử lý ngoại lệ (Exception Handling)
- Thực hành với generic types
- Tìm hiểu về collections framework