Hướng dẫn Adapter Pattern trong Java
1. Giới thiệu Adapter Pattern
Adapter Pattern là một mẫu thiết kế thuộc nhóm Structural Patterns, được sử dụng để cho phép các interface không tương thích có thể làm việc cùng nhau. Adapter Pattern hoạt động như một bộ chuyển đổi, chuyển đổi interface của một lớp này thành interface mà một lớp khác mong muốn.
2. Các trường hợp ứng dụng Adapter Pattern
Tích hợp hệ thống cũ: Khi cần tích hợp các hệ thống hoặc lớp cũ với hệ thống mới mà các interface không tương thích.
Sử dụng lại mã nguồn: Khi muốn sử dụng lại các lớp hiện có nhưng interface không khớp với yêu cầu hiện tại.
Chuyển đổi dữ liệu: Khi cần chuyển đổi dữ liệu giữa các hệ thống hoặc lớp khác nhau.
3. Triển khai Adapter Pattern
3.1. Ví dụ triển khai đơn giản
Giả sử chúng ta có một interface MediaPlayer và một lớp cũ AudioPlayer chỉ chơi các file âm thanh định dạng MP3. Chúng ta muốn tích hợp một lớp mới MediaAdapter để chơi cả định dạng MP4 và VLC.
// Bước 1: Tạo interface MediaPlayer
public interface MediaPlayer {
void play(String audioType, String fileName);
}
// Bước 2: Tạo các lớp cũ
public class AudioPlayer implements MediaPlayer {
@Override
public void play(String audioType, String fileName) {
if(audioType.equalsIgnoreCase("mp3")) {
System.out.println("Playing mp3 file. Name: " + fileName);
} else {
System.out.println("Invalid media. " + audioType + " format not supported");
}
}
}
// Bước 3: Tạo các interface và lớp cho định dạng mới
public interface AdvancedMediaPlayer {
void playVlc(String fileName);
void playMp4(String fileName);
}
public class VlcPlayer implements AdvancedMediaPlayer {
@Override
public void playVlc(String fileName) {
System.out.println("Playing vlc file. Name: " + fileName);
}
@Override
public void playMp4(String fileName) {
// Do nothing
}
}
public class Mp4Player implements AdvancedMediaPlayer {
@Override
public void playVlc(String fileName) {
// Do nothing
}
@Override
public void playMp4(String fileName) {
System.out.println("Playing mp4 file. Name: " + fileName);
}
}
// Bước 4: Tạo lớp Adapter
public class MediaAdapter implements MediaPlayer {
AdvancedMediaPlayer advancedMusicPlayer;
public MediaAdapter(String audioType) {
if(audioType.equalsIgnoreCase("vlc")) {
advancedMusicPlayer = new VlcPlayer();
} else if(audioType.equalsIgnoreCase("mp4")) {
advancedMusicPlayer = new Mp4Player();
}
}
@Override
public void play(String audioType, String fileName) {
if(audioType.equalsIgnoreCase("vlc")) {
advancedMusicPlayer.playVlc(fileName);
} else if(audioType.equalsIgnoreCase("mp4")) {
advancedMusicPlayer.playMp4(fileName);
}
}
}
// Bước 5: Tích hợp Adapter vào lớp AudioPlayer
public class AudioPlayer implements MediaPlayer {
MediaAdapter mediaAdapter;
@Override
public void play(String audioType, String fileName) {
if(audioType.equalsIgnoreCase("mp3")) {
System.out.println("Playing mp3 file. Name: " + fileName);
} else if(audioType.equalsIgnoreCase("vlc") || audioType.equalsIgnoreCase("mp4")) {
mediaAdapter = new MediaAdapter(audioType);
mediaAdapter.play(audioType, fileName);
} else {
System.out.println("Invalid media. " + audioType + " format not supported");
}
}
}
// Bước 6: Sử dụng Adapter Pattern
public class AdapterPatternDemo {
public static void main(String[] args) {
AudioPlayer audioPlayer = new AudioPlayer();
audioPlayer.play("mp3", "beyond the horizon.mp3");
audioPlayer.play("mp4", "alone.mp4");
audioPlayer.play("vlc", "far far away.vlc");
audioPlayer.play("avi", "mind me.avi");
}
}
3.2. Ví dụ triển khai phức tạp
Giả sử chúng ta có một hệ thống thanh toán cũ OldPaymentSystem và muốn tích hợp với một hệ thống thanh toán mới NewPaymentSystem.
// Bước 1: Tạo interface cho hệ thống thanh toán cũ
public interface OldPaymentSystem {
void processPayment(String paymentType, double amount);
}
// Bước 2: Tạo lớp cũ OldPaymentSystemImpl
public class OldPaymentSystemImpl implements OldPaymentSystem {
@Override
public void processPayment(String paymentType, double amount) {
System.out.println("Processing " + paymentType + " payment of amount: " + amount);
}
}
// Bước 3: Tạo interface cho hệ thống thanh toán mới
public interface NewPaymentSystem {
void makePayment(String paymentType, double amount);
}
// Bước 4: Tạo lớp mới NewPaymentSystemImpl
public class NewPaymentSystemImpl implements NewPaymentSystem {
@Override
public void makePayment(String paymentType, double amount) {
System.out.println("Making " + paymentType + " payment of amount: " + amount);
}
}
// Bước 5: Tạo lớp Adapter
public class PaymentAdapter implements OldPaymentSystem {
private NewPaymentSystem newPaymentSystem;
public PaymentAdapter(NewPaymentSystem newPaymentSystem) {
this.newPaymentSystem = newPaymentSystem;
}
@Override
public void processPayment(String paymentType, double amount) {
newPaymentSystem.makePayment(paymentType, amount);
}
}
// Bước 6: Sử dụng Adapter Pattern
public class AdapterPatternDemo {
public static void main(String[] args) {
OldPaymentSystem oldPaymentSystem = new OldPaymentSystemImpl();
oldPaymentSystem.processPayment("Credit Card", 100.0);
NewPaymentSystem newPaymentSystem = new NewPaymentSystemImpl();
OldPaymentSystem paymentAdapter = new PaymentAdapter(newPaymentSystem);
paymentAdapter.processPayment("Debit Card", 200.0);
}
}
4. Phân tích các trường hợp ứng dụng Adapter Pattern
4.1. Tích hợp hệ thống cũ
Ưu điểm: Cho phép tích hợp các hệ thống cũ mà không cần sửa đổi mã nguồn hiện có.
Nhược điểm: Cần đảm bảo rằng adapter hoạt động chính xác và không gây lỗi trong quá trình tích hợp.
4.2. Sử dụng lại mã nguồn
Ưu điểm: Tận dụng lại các lớp hiện có mà không cần viết lại mã nguồn, giúp tiết kiệm thời gian và công sức.
Nhược điểm: Cần đảm bảo rằng adapter không làm giảm hiệu suất của hệ thống.
4.3. Chuyển đổi dữ liệu
Ưu điểm: Giúp chuyển đổi dữ liệu giữa các hệ thống hoặc lớp khác nhau một cách dễ dàng và hiệu quả.
Nhược điểm: Cần kiểm tra kỹ lưỡng để đảm bảo rằng dữ liệu được chuyển đổi chính xác và không bị mất mát.
5. Kết luận
Adapter Pattern là một mẫu thiết kế mạnh mẽ và hữu ích, đặc biệt khi cần tích hợp các hệ thống hoặc lớp không tương thích trong Java. Việc hiểu và áp dụng đúng Adapter Pattern sẽ giúp lập trình viên xây dựng các hệ thống dễ bảo trì, dễ mở rộng và hiệu quả hơn.