Adapter design pattern là một trong những mẫu thiết kế cấu trúc, được sử dụng để giúp hai interface không liên quan có thể làm việc cùng nhau. Đối tượng kết nối hai interface không liên quan này được gọi là Adapter (bộ chuyển đổi).

Giới thiệu về Adapter Design Pattern
Một ví dụ thực tế rất điển hình cho Adapter design pattern là bộ sạc điện thoại. Pin điện thoại cần 3 volt để sạc, trong khi ổ điện thông thường tạo ra điện áp 120V (ở Mỹ) hoặc 240V (ở Ấn Độ). Do đó, bộ sạc điện thoại đóng vai trò như một adapter giữa ổ điện tường và cổng sạc của điện thoại.
Trong hướng dẫn này, chúng ta sẽ thử triển khai một adapter đa năng bằng cách sử dụng adapter design pattern. Trước tiên, chúng ta sẽ có hai lớp – Volt (để đo điện áp) và Socket (tạo ra điện áp cố định 120V).
package com.journaldev.design.adapter;
public class Volt {
private int volts;
public Volt(int v){
this.volts=v;
}
public int getVolts() {
return volts;
}
public void setVolts(int volts) {
this.volts = volts;
}
}
package com.journaldev.design.adapter;
public class Socket {
public Volt getVolt(){
return new Volt(120);
}
}
Bây giờ chúng ta muốn xây dựng một adapter có thể tạo ra điện áp 3 volt, 12 volt và mặc định là 120 volt. Vì vậy, trước hết chúng ta sẽ tạo một adapter interface với các phương thức tương ứng.
package com.journaldev.design.adapter;
public interface SocketAdapter {
public Volt get120Volt();
public Volt get12Volt();
public Volt get3Volt();
}
Mẫu Adapter hai chiều
Khi triển khai Adapter pattern, có hai cách tiếp cận – class adapter và object adapter – tuy nhiên, cả hai cách đều cho ra kết quả giống nhau.
- Class Adapter – Cách tiếp cận này sử dụng kế thừa trong Java và mở rộng từ interface nguồn, trong ví dụ này là lớp Socket.
- Object Adapter – Cách tiếp cận này sử dụng composition trong Java, trong đó adapter chứa đối tượng nguồn.
Adapter Design Pattern – Class Adapter
Dưới đây là phần triển khai class adapter cho adapter của chúng ta.
package com.journaldev.design.adapter;
//Using inheritance for adapter pattern
public class SocketClassAdapterImpl extends Socket implements SocketAdapter{
@Override
public Volt get120Volt() {
return getVolt();
}
@Override
public Volt get12Volt() {
Volt v= getVolt();
return convertVolt(v,10);
}
@Override
public Volt get3Volt() {
Volt v= getVolt();
return convertVolt(v,40);
}
private Volt convertVolt(Volt v, int i) {
return new Volt(v.getVolts()/i);
}
}
Adapter Design Pattern – Triển khai Object Adapter
Dưới đây là phần triển khai Object adapter cho adapter của chúng ta.
package com.journaldev.design.adapter;
public class SocketObjectAdapterImpl implements SocketAdapter{
//Using Composition for adapter pattern
private Socket sock = new Socket();
@Override
public Volt get120Volt() {
return sock.getVolt();
}
@Override
public Volt get12Volt() {
Volt v= sock.getVolt();
return convertVolt(v,10);
}
@Override
public Volt get3Volt() {
Volt v= sock.getVolt();
return convertVolt(v,40);
}
private Volt convertVolt(Volt v, int i) {
return new Volt(v.getVolts()/i);
}
}
Lưu ý rằng cả hai cách triển khai adapter đều gần như giống nhau và đều hiện thực interface SocketAdapter. Interface adapter này cũng có thể là một abstract class. Dưới đây là chương trình kiểm thử để sử dụng phần triển khai adapter design pattern của chúng ta.
package com.journaldev.design.test;
import com.journaldev.design.adapter.SocketAdapter;
import com.journaldev.design.adapter.SocketClassAdapterImpl;
import com.journaldev.design.adapter.SocketObjectAdapterImpl;
import com.journaldev.design.adapter.Volt;
public class AdapterPatternTest {
public static void main(String[] args) {
testClassAdapter();
testObjectAdapter();
}
private static void testObjectAdapter() {
SocketAdapter sockAdapter = new SocketObjectAdapterImpl();
Volt v3 = getVolt(sockAdapter,3);
Volt v12 = getVolt(sockAdapter,12);
Volt v120 = getVolt(sockAdapter,120);
System.out.println("v3 volts using Object Adapter="+v3.getVolts());
System.out.println("v12 volts using Object Adapter="+v12.getVolts());
System.out.println("v120 volts using Object Adapter="+v120.getVolts());
}
private static void testClassAdapter() {
SocketAdapter sockAdapter = new SocketClassAdapterImpl();
Volt v3 = getVolt(sockAdapter,3);
Volt v12 = getVolt(sockAdapter,12);
Volt v120 = getVolt(sockAdapter,120);
System.out.println("v3 volts using Class Adapter="+v3.getVolts());
System.out.println("v12 volts using Class Adapter="+v12.getVolts());
System.out.println("v120 volts using Class Adapter="+v120.getVolts());
}
private static Volt getVolt(SocketAdapter sockAdapter, int i) {
switch (i){
case 3: return sockAdapter.get3Volt();
case 12: return sockAdapter.get12Volt();
case 120: return sockAdapter.get120Volt();
default: return sockAdapter.get120Volt();
}
}
}
Khi chạy chương trình kiểm thử trên, chúng ta sẽ nhận được kết quả sau.
v3 volts using Class Adapter=3
v12 volts using Class Adapter=12
v120 volts using Class Adapter=120
v3 volts using Object Adapter=3
v12 volts using Object Adapter=12
v120 volts using Object Adapter=120
Sơ đồ lớp của Adapter Pattern

Ví dụ Adapter Design Pattern trong JDK
Một số ví dụ về adapter design pattern dễ dàng tìm thấy trong các lớp của JDK bao gồm;
- java.util.Arrays#asList()
- java.io.InputStreamReader(InputStream) (trả về một Reader)
- java.io.OutputStreamWriter(OutputStream) (trả về một Writer)
Vậy là bạn đã nắm được tổng quan về adapter design pattern trong Java.