一、模式定义
适配器模式是一种结构型设计模式,它允许不兼容的接口之间能够协同工作。适配器模式通过将一个类的接口转换成客户期望的另一个接口,使得原本由于接口不兼容而不能一起工作的类可以一起工作。
二、Java源代码实现
1. 类适配器(通过继承实现)
// 1. 目标接口(Target) - 客户端期望的接口
public interface MediaPlayer {
void play(String audioType, String fileName);
// 默认方法
default void stop() {
System.out.println("停止播放");
}
}
// 2. 被适配者(Adaptee) - 已存在的、不兼容的接口
public class AdvancedMediaPlayer {
public void playVlc(String fileName) {
System.out.println("播放VLC文件: " + fileName);
}
public void playMp4(String fileName) {
System.out.println("播放MP4文件: " + fileName);
}
public void playAvi(String fileName) {
System.out.println("播放AVI文件: " + fileName);
}
public void stopPlaying() {
System.out.println("停止播放");
}
public void setVolume(int volume) {
System.out.println("设置音量: " + volume);
}
}
// 3. 类适配器 - 通过继承被适配者实现目标接口
public class MediaAdapter extends AdvancedMediaPlayer implements MediaPlayer {
@Override
public void play(String audioType, String fileName) {
if (audioType.equalsIgnoreCase("vlc")) {
playVlc(fileName);
} else if (audioType.equalsIgnoreCase("mp4")) {
playMp4(fileName);
} else if (audioType.equalsIgnoreCase("avi")) {
playAvi(fileName);
} else {
System.out.println("不支持的文件格式: " + audioType);
}
}
// 可以添加额外的适配方法
public void playWithVolume(String audioType, String fileName, int volume) {
play(audioType, fileName);
setVolume(volume);
}
}
2. 对象适配器(通过组合实现)
// 1. 目标接口
public interface MediaPlayer {
void play(String audioType, String fileName);
void stop();
// 新增功能
void setVolume(int volume);
int getCurrentTime();
// 默认方法
default boolean isPlaying() {
return false;
}
}
// 2. 被适配者接口
public interface AdvancedMediaPlayer {
void playVlc(String fileName);
void playMp4(String fileName);
void playMkv(String fileName);
void playFlv(String fileName);
void stop();
void setVolume(int volume);
int getCurrentPosition();
}
// 3. 具体被适配者实现
public class VlcPlayer implements AdvancedMediaPlayer {
private boolean isPlaying = false;
private int currentPosition = 0;
private int volume = 50;
@Override
public void playVlc(String fileName) {
isPlaying = true;
currentPosition = 0;
System.out.println("VLC播放器正在播放: " + fileName);
}
@Override
public void playMp4(String fileName) {
throw new UnsupportedOperationException("VLC播放器不支持MP4格式");
}
@Override
public void playMkv(String fileName) {
throw new UnsupportedOperationException("VLC播放器不支持MKV格式");
}
@Override
public void playFlv(String fileName) {
throw new UnsupportedOperationException("VLC播放器不支持FLV格式");
}
@Override
public void stop() {
isPlaying = false;
System.out.println("VLC播放器停止播放");
}
@Override
public void setVolume(int volume) {
this.volume = volume;
System.out.println("VLC播放器音量设置为: " + volume);
}
@Override
public int getCurrentPosition() {
return currentPosition;
}
}
public class Mp4Player implements AdvancedMediaPlayer {
private boolean isPlaying = false;
private int currentPosition = 0;
private int volume = 50;
@Override
public void playVlc(String fileName) {
throw new UnsupportedOperationException("MP4播放器不支持VLC格式");
}
@Override
public void playMp4(String fileName) {
isPlaying = true;
currentPosition = 0;
System.out.println("MP4播放器正在播放: " + fileName);
}
@Override
public void playMkv(String fileName) {
throw new UnsupportedOperationException("MP4播放器不支持MKV格式");
}
@Override
public void playFlv(String fileName) {
throw new UnsupportedOperationException("MP4播放器不支持FLV格式");
}
@Override
public void stop() {
isPlaying = false;
System.out.println("MP4播放器停止播放");
}
@Override
public void setVolume(int volume) {
this.volume = volume;
System.out.println("MP4播放器音量设置为: " + volume);
}
@Override
public int getCurrentPosition() {
return currentPosition;
}
}
// 4. 对象适配器 - 通过组合被适配者实现目标接口
public class MediaAdapter implements MediaPlayer {
// 组合被适配者
private AdvancedMediaPlayer advancedMusicPlayer;
private String currentFile;
private boolean isPlaying = false;
private int currentTime = 0;
public MediaAdapter(String audioType) {
if (audioType.equalsIgnoreCase("vlc")) {
advancedMusicPlayer = new VlcPlayer();
} else if (audioType.equalsIgnoreCase("mp4")) {
advancedMusicPlayer = new Mp4Player();
} else {
throw new IllegalArgumentException("不支持的文件格式: " + audioType);
}
}
// 也可以直接传入被适配者
public MediaAdapter(AdvancedMediaPlayer player) {
this.advancedMusicPlayer = player;
}
@Override
public void play(String audioType, String fileName) {
this.currentFile = fileName;
if (audioType.equalsIgnoreCase("vlc")) {
advancedMusicPlayer.playVlc(fileName);
isPlaying = true;
} else if (audioType.equalsIgnoreCase("mp4")) {
advancedMusicPlayer.playMp4(fileName);
isPlaying = true;
} else if (audioType.equalsIgnoreCase("mkv") || audioType.equalsIgnoreCase("flv")) {
System.out.println("暂时不支持 " + audioType + " 格式,正在转换为兼容格式...");
// 模拟格式转换
String convertedFile = convertFormat(fileName, audioType, "mp4");
advancedMusicPlayer.playMp4(convertedFile);
isPlaying = true;
} else {
System.out.println("不支持的文件格式: " + audioType);
}
}
@Override
public void stop() {
if (isPlaying) {
advancedMusicPlayer.stop();
isPlaying = false;
}
}
@Override
public void setVolume(int volume) {
advancedMusicPlayer.setVolume(volume);
}
@Override
public int getCurrentTime() {
if (isPlaying) {
return advancedMusicPlayer.getCurrentPosition();
}
return currentTime;
}
@Override
public boolean isPlaying() {
return isPlaying;
}
// 适配器可以添加额外功能
public String getCurrentFile() {
return currentFile;
}
public String getPlayerType() {
return advancedMusicPlayer.getClass().getSimpleName();
}
// 格式转换方法
private String convertFormat(String fileName, String fromFormat, String toFormat) {
String baseName = fileName.substring(0, fileName.lastIndexOf('.'));
return baseName + "." + toFormat.toLowerCase();
}
}
// 5. 客户端使用
public class AudioPlayer implements MediaPlayer {
private MediaAdapter mediaAdapter;
@Override
public void play(String audioType, String fileName) {
// 内置支持mp3格式
if (audioType.equalsIgnoreCase("mp3")) {
System.out.println("播放MP3文件: " + fileName);
}
// 使用适配器播放其他格式
else if (audioType.equalsIgnoreCase("vlc")
|| audioType.equalsIgnoreCase("mp4")
|| audioType.equalsIgnoreCase("mkv")
|| audioType.equalsIgnoreCase("flv")) {
mediaAdapter = new MediaAdapter(audioType);
mediaAdapter.play(audioType, fileName);
} else {
System.out.println("不支持的文件格式: " + audioType);
}
}
@Override
public void stop() {
if (mediaAdapter != null) {
mediaAdapter.stop();
} else {
System.out.println("停止播放MP3");
}
}
@Override
public void setVolume(int volume) {
if (mediaAdapter != null) {
mediaAdapter.setVolume(volume);
} else {
System.out.println("设置MP3播放器音量: " + volume);
}
}
@Override
public int getCurrentTime() {
if (mediaAdapter != null) {
return mediaAdapter.getCurrentTime();
}
return 0;
}
}
3. 双向适配器
// 1. 目标接口A
public interface NewLogger {
void log(String message);
void error(String error);
void warn(String warning);
default void log(String level, String message) {
System.out.println("[" + level + "] " + message);
}
}
// 2. 目标接口B
public interface LegacyLogger {
void writeLog(String log);
void writeError(String error);
void writeWarning(String warning);
void setLogLevel(int level);
int getLogLevel();
}
// 3. 具体实现
implements NewLogger {
@Override
public void log(String message) {
System.out.println("[INFO] " + message);
}
@Override
public void error(String error) {
System.out.println("[ERROR] " + error);
}
@Override
public void warn(String warning) {
System.out.println("[WARN] " + warning);
}
}
public class OldLogger implements LegacyLogger {
private int logLevel = 1; // 1=INFO, 2=WARN, 3=ERROR
@Override
public void writeLog(String log) {
if (logLevel <= 1) {
System.out.println("LOG: " + log);
}
}
@Override
public void writeError(String error) {
if (logLevel <= 3) {
System.out.println("ERROR: " + error);
}
}
@Override
public void writeWarning(String warning) {
if (logLevel <= 2) {
System.out.println("WARNING: " + warning);
}
}
@Override
public void setLogLevel(int level) {
this.logLevel = level;
}
@Override
public int getLogLevel() {
return logLevel;
}
}
// 4. 双向适配器 - 实现两个接口
public class TwoWayLoggerAdapter implements NewLogger, LegacyLogger {
private NewLogger newLogger;
private LegacyLogger legacyLogger;
public TwoWayLoggerAdapter(NewLogger newLogger) {
this.newLogger = newLogger;
this.legacyLogger = new LegacyLogger() {
@Override
public void writeLog(String log) {
newLogger.log(log);
}
@Override
public void writeError(String error) {
newLogger.error(error);
}
@Override
public void writeWarning(String warning) {
newLogger.warn(warning);
}
@Override
public void setLogLevel(int level) {
// 忽略,新日志系统不使用级别
}
@Override
public int getLogLevel() {
return 1;
}
};
}
public TwoWayLoggerAdapter(LegacyLogger legacyLogger) {
this.legacyLogger = legacyLogger;
this.newLogger = new NewLogger() {
@Override
public void log(String message) {
legacyLogger.writeLog(message);
}
@Override
public void error(String error) {
legacyLogger.writeError(error);
}
@Override
public void warn(String warning) {
legacyLogger.writeWarning(warning);
}
};
}
// 实现NewLogger接口
@Override
public void log(String message) {
legacyLogger.writeLog(message);
}
@Override
public void error(String error) {
legacyLogger.writeError(error);
}
@Override
public void warn(String warning) {
legacyLogger.writeWarning(warning);
}
// 实现LegacyLogger接口
@Override
public void writeLog(String log) {
newLogger.log(log);
}
@Override
public void writeError(String error) {
newLogger.error(error);
}
@Override
public void writeWarning(String warning) {
newLogger.warn(warning);
}
@Override
public void setLogLevel(int level) {
legacyLogger.setLogLevel(level);
}
@Override
public int getLogLevel() {
return legacyLogger.getLogLevel();
}
}
4. 默认适配器(接口适配器)
// 1. 大接口 - 包含很多方法
public interface FileOperations {
void open(String fileName);
void close();
void read();
void write(String content);
void delete();
void rename(String newName);
void copy(String destination);
void move(String destination);
void setPermissions(int permissions);
int getSize();
String getContent();
boolean exists();
boolean isDirectory();
boolean isFile();
Date getLastModified();
void setLastModified(Date date);
}
// 2. 默认适配器 - 提供空实现
public abstract class FileOperationsAdapter implements FileOperations {
@Override
public void open(String fileName) {
// 默认实现
}
@Override
public void close() {
// 默认实现
}
@Override
public void read() {
// 默认实现
}
@Override
public void write(String content) {
// 默认实现
}
@Override
public void delete() {
// 默认实现
}
@Override
public void rename(String newName) {
// 默认实现
}
@Override
public void copy(String destination) {
// 默认实现
}
@Override
public void move(String destination) {
// 默认实现
}
@Override
public void setPermissions(int permissions) {
// 默认实现
}
@Override
public int getSize() {
return 0;
}
@Override
public String getContent() {
return "";
}
@Override
public boolean exists() {
return false;
}
@Override
public boolean isDirectory() {
return false;
}
@Override
public boolean isFile() {
return false;
}
@Override
public Date getLastModified() {
return new Date();
}
@Override
public void setLastModified(Date date) {
// 默认实现
}
}
// 3. 具体实现 - 只需要实现需要的方法
public class SimpleFileReader extends FileOperationsAdapter {
private String fileName;
private String content = "";
public SimpleFileReader(String fileName) {
this.fileName = fileName;
}
@Override
public void open(String fileName) {
this.fileName = fileName;
System.out.println("打开文件: " + fileName);
}
@Override
public void read() {
// 模拟读取文件
content = "这是文件 " + fileName + " 的内容";
System.out.println("读取文件: " + fileName);
}
@Override
public String getContent() {
return content;
}
@Override
public boolean exists() {
return true; // 假设文件存在
}
// 只需要实现需要的方法,其他方法使用默认实现
}
// 4. 只读文件适配器
public class ReadOnlyFileAdapter extends FileOperationsAdapter {
private String fileName;
public ReadOnlyFileAdapter(String fileName) {
this.fileName = fileName;
}
@Override
public void open(String fileName) {
this.fileName = fileName;
System.out.println("以只读方式打开文件: " + fileName);
}
@Override
public void read() {
System.out.println("读取文件内容");
}
@Override
public String getContent() {
return "只读文件内容";
}
// 重写修改方法,抛出异常
@Override
public void write(String content) {
throw new UnsupportedOperationException("只读文件,不能写入");
}
@Override
public void delete() {
throw new UnsupportedOperationException("只读文件,不能删除");
}
@Override
public void rename(String newName) {
throw new UnsupportedOperationException("只读文件,不能重命名");
}
}
5. 客户端使用示例
public class AdapterPatternDemo {
public static void main(String[] args) {
System.out.println("=== 适配器模式示例 ===\n");
// 测试对象适配器
testObjectAdapter();
// 测试类适配器
testClassAdapter();
// 测试双向适配器
testTwoWayAdapter();
// 测试默认适配器
testDefaultAdapter();
// 测试实际场景
testRealWorldScenario();
}
private static void testObjectAdapter() {
System.out.println("1. 对象适配器示例:");
AudioPlayer audioPlayer = new AudioPlayer();
// 播放各种格式
audioPlayer.play("mp3", "song.mp3");
audioPlayer.play("mp4", "movie.mp4");
audioPlayer.play("vlc", "video.vlc");
audioPlayer.play("mkv", "film.mkv");
audioPlayer.play("avi", "video.avi");
// 控制播放
audioPlayer.setVolume(80);
System.out.println("当前时间: " + audioPlayer.getCurrentTime());
audioPlayer.stop();
}
private static void testClassAdapter() {
System.out.println("\n2. 类适配器示例:");
MediaAdapter adapter = new MediaAdapter();
// 使用适配器播放
adapter.play("vlc", "video.vlc");
adapter.play("mp4", "movie.mp4");
// 使用额外功能
adapter.playWithVolume("avi", "film.avi", 75);
adapter.stop();
}
private static void testTwoWayAdapter() {
System.out.println("\n3. 双向适配器示例:");
// 新系统使用旧日志
ModernLogger modernLogger = new ModernLogger();
TwoWayLoggerAdapter adapter1 = new TwoWayLoggerAdapter(modernLogger);
// 通过LegacyLogger接口调用
adapter1.writeLog("通过LegacyLogger接口记录日志");
adapter1.writeError("通过LegacyLogger接口记录错误");
// 旧系统使用新日志
OldLogger oldLogger = new OldLogger();
TwoWayLoggerAdapter adapter2 = new TwoWayLoggerAdapter(oldLogger);
// 通过NewLogger接口调用
adapter2.log("通过NewLogger接口记录日志");
adapter2.error("通过NewLogger接口记录错误");
}
private static void testDefaultAdapter() {
System.out.println("\n4. 默认适配器示例:");
// 使用简单文件阅读器
SimpleFileReader reader = new SimpleFileReader("test.txt");
reader.open("test.txt");
reader.read();
System.out.println("文件内容: " + reader.getContent());
// 使用只读文件适配器
ReadOnlyFileAdapter readOnlyFile = new ReadOnlyFileAdapter("readonly.txt");
readOnlyFile.open("readonly.txt");
readOnlyFile.read();
try {
readOnlyFile.write("新内容");
} catch (UnsupportedOperationException e) {
System.out.println("预期异常: " + e.getMessage());
}
}
private static void testRealWorldScenario() {
System.out.println("\n5. 实际场景示例:");
// 场景:旧支付系统适配
PaymentSystem paymentSystem = new PaymentSystem();
paymentSystem.processPayments();
}
}
// 实际场景示例:支付系统适配
interface NewPaymentGateway {
boolean authorizePayment(String cardNumber, double amount);
boolean capturePayment(String transactionId);
boolean refundPayment(String transactionId, double amount);
String getPaymentStatus(String transactionId);
}
class PayPalGateway implements NewPaymentGateway {
@Override
public boolean authorizePayment(String cardNumber, double amount) {
System.out.println("PayPal: 授权支付 " + amount + " 元,卡号: " + cardNumber);
return true;
}
@Override
public boolean capturePayment(String transactionId) {
System.out.println("PayPal: 捕获交易 " + transactionId);
return true;
}
@Override
public boolean refundPayment(String transactionId, double amount) {
System.out.println("PayPal: 退款 " + amount + " 元,交易号: " + transactionId);
return true;
}
@Override
public String getPaymentStatus(String transactionId) {
return "COMPLETED";
}
}
// 旧的支付接口
interface LegacyPaymentSystem {
boolean processCreditCard(String cardNumber, String expiryDate, String cvv, double amount);
boolean processRefund(String orderId, double amount);
String checkTransactionStatus(String orderId);
}
class OldPaymentSystem implements LegacyPaymentSystem {
@Override
public boolean processCreditCard(String cardNumber, String expiryDate, String cvv, double amount) {
System.out.println("旧系统: 处理信用卡支付,卡号: " + cardNumber +
", 有效期: " + expiryDate +
", 金额: " + amount);
return true;
}
@Override
public boolean processRefund(String orderId, double amount) {
System.out.println("旧系统: 处理退款,订单号: " + orderId + ", 金额: " + amount);
return true;
}
@Override
public String checkTransactionStatus(String orderId) {
return "SUCCESS";
}
}
// 支付适配器
class PaymentAdapter implements NewPaymentGateway {
private LegacyPaymentSystem legacyPaymentSystem;
public PaymentAdapter(LegacyPaymentSystem legacyPaymentSystem) {
this.legacyPaymentSystem = legacyPaymentSystem;
}
@Override
public boolean authorizePayment(String cardNumber, double amount) {
// 模拟从卡号中提取有效期和CVV
String expiryDate = "12/26"; // 模拟
String cvv = "123"; // 模拟
return legacyPaymentSystem.processCreditCard(cardNumber, expiryDate, cvv, amount);
}
@Override
public boolean capturePayment(String transactionId) {
// 旧系统没有单独的捕获步骤,所以直接返回成功
System.out.println("适配器: 自动捕获交易 " + transactionId);
return true;
}
@Override
public boolean refundPayment(String transactionId, double amount) {
return legacyPaymentSystem.processRefund(transactionId, amount);
}
@Override
public String getPaymentStatus(String transactionId) {
return legacyPaymentSystem.checkTransactionStatus(transactionId);
}
}
// 支付系统
class PaymentSystem {
public void processPayments() {
System.out.println("\n支付系统演示:");
// 使用新的支付网关
NewPaymentGateway payPal = new PayPalGateway();
payPal.authorizePayment("4111111111111111", 100.00);
// 通过适配器使用旧的支付系统
LegacyPaymentSystem oldSystem = new OldPaymentSystem();
NewPaymentGateway adaptedSystem = new PaymentAdapter(oldSystem);
adaptedSystem.authorizePayment("4222222222222222", 200.00);
adaptedSystem.capturePayment("TXN12345");
adaptedSystem.refundPayment("TXN12345", 50.00);
String status = adaptedSystem.getPaymentStatus("TXN12345");
System.out.println("交易状态: " + status);
}
}
三、应用场景深度解析
1. 系统集成和遗留系统适配
// 场景:新旧系统集成
public class SystemIntegrationExample {
// 新系统接口
interface ModernDataService {
JsonObject fetchData(String query);
void saveData(JsonObject data);
}
// 旧系统接口
interface LegacyDataService {
String getData(String sql);
void insertData(String table, Map<String, String> data);
}
// 适配器
class DataServiceAdapter implements ModernDataService {
private LegacyDataService legacyService;
public DataServiceAdapter(LegacyDataService legacyService) {
this.legacyService = legacyService;
}
@Override
public JsonObject fetchData(String query) {
// 将现代查询转换为SQL
String sql = convertToSql(query);
String data = legacyService.getData(sql);
// 将字符串转换为JSON
return convertToJson(data);
}
@Override
public void saveData(JsonObject data) {
// 将JSON转换为表数据
Map<String, String> tableData = convertToTableData(data);
legacyService.insertData("modern_table", tableData);
}
private String convertToSql(String query) {
// 转换逻辑
return "SELECT * FROM table WHERE " + query;
}
private JsonObject convertToJson(String data) {
// 转换逻辑
return new JsonObject();
}
private Map<String, String> convertToTableData(JsonObject json) {
// 转换逻辑
return new HashMap<>();
}
}
class JsonObject {
// JSON对象实现
}
}
2. 第三方库和API适配
// 场景:统一不同地图服务API
public class MapServiceAdapterExample {
// 统一地图接口
interface MapService {
Location geocode(String address);
Route calculateRoute(Location start, Location end);
List<Location> searchNearby(Location center, String keyword);
}
// Google Maps适配
class GoogleMapsAdapter implements MapService {
private GoogleMapsService googleMaps;
public GoogleMapsAdapter(GoogleMapsService googleMaps) {
this.googleMaps = googleMaps;
}
@Override
public Location geocode(String address) {
GoogleGeocodeResult result = googleMaps.geocode(address);
return convertToLocation(result);
}
@Override
public Route calculateRoute(Location start, Location end) {
GoogleRoute googleRoute = googleMaps.getDirections(
convertToGoogleLocation(start),
convertToGoogleLocation(end)
);
return convertToRoute(googleRoute);
}
// 转换方法...
}
// Baidu Maps适配
class BaiduMapsAdapter implements MapService {
private BaiduMapsService baiduMaps;
public BaiduMapsAdapter(BaiduMapsService baiduMaps) {
this.baiduMaps = baiduMaps;
}
@Override
public Location geocode(String address) {
BaiduGeocodeResult result = baiduMaps.geocode(address);
return convertToLocation(result);
}
// 其他方法实现...
}
// 使用
class MapClient {
private MapService mapService;
public void setMapProvider(String provider) {
if (provider.equals("google")) {
mapService = new GoogleMapsAdapter(new GoogleMapsService());
} else if (provider.equals("baidu")) {
mapService = new BaiduMapsAdapter(new BaiduMapsService());
}
}
public void findRoute(String startAddress, String endAddress) {
Location start = mapService.geocode(startAddress);
Location end = mapService.geocode(endAddress);
Route route = mapService.calculateRoute(start, end);
// 使用路由...
}
}
}
3. 数据库驱动适配
// 场景:统一数据库访问接口
public class DatabaseAdapterExample {
// 统一数据库接口
interface Database {
Connection connect(String url, String username, String password);
ResultSet executeQuery(String sql);
int executeUpdate(String sql);
void close();
}
// MySQL适配器
class MySQLAdapter implements Database {
private com.mysql.jdbc.Connection mysqlConn;
@Override
public Connection connect(String url, String username, String password) {
mysqlConn = com.mysql.jdbc.DriverManager.getConnection(
"jdbc:mysql://" + url, username, password);
return new ConnectionAdapter(mysqlConn);
}
@Override
public ResultSet executeQuery(String sql) {
com.mysql.jdbc.ResultSet rs = mysqlConn.executeQuery(sql);
return new ResultSetAdapter(rs);
}
// 其他方法...
}
// PostgreSQL适配器
class PostgreSQLAdapter implements Database {
private org.postgresql.Connection pgConn;
@Override
public Connection connect(String url, String username, String password) {
pgConn = org.postgresql.DriverManager.getConnection(
"jdbc:postgresql://" + url, username, password);
return new ConnectionAdapter(pgConn);
}
// 其他方法...
}
// 连接适配器
class ConnectionAdapter implements Connection {
private Object nativeConnection;
public ConnectionAdapter(Object nativeConnection) {
this.nativeConnection = nativeConnection;
}
// 实现统一连接接口...
}
}
4. UI组件适配
// 场景:适配不同UI框架组件
public class UIComponentAdapterExample {
// 统一UI组件接口
interface UIComponent {
void render();
void setText(String text);
String getText();
void setEnabled(boolean enabled);
void addClickListener(ClickListener listener);
}
// Swing按钮适配器
class SwingButtonAdapter implements UIComponent {
private JButton swingButton;
public SwingButtonAdapter(JButton button) {
this.swingButton = button;
}
@Override
public void render() {
swingButton.setVisible(true);
}
@Override
public void setText(String text) {
swingButton.setText(text);
}
@Override
public String getText() {
return swingButton.getText();
}
@Override
public void setEnabled(boolean enabled) {
swingButton.setEnabled(enabled);
}
@Override
public void addClickListener(ClickListener listener) {
swingButton.addActionListener(e -> listener.onClick());
}
}
// JavaFX按钮适配器
class JavaFXButtonAdapter implements UIComponent {
private Button fxButton;
public JavaFXButtonAdapter(Button button) {
this.fxButton = button;
}
@Override
public void render() {
fxButton.setVisible(true);
}
@Override
public void setText(String text) {
fxButton.setText(text);
}
@Override
public String getText() {
return fxButton.getText();
}
@Override
public void setEnabled(boolean enabled) {
fxButton.setDisable(!enabled);
}
@Override
public void addClickListener(ClickListener listener) {
fxButton.setOnAction(e -> listener.onClick());
}
}
// Web按钮适配器
class WebButtonAdapter implements UIComponent {
private WebElement webButton;
public WebButtonAdapter(WebElement button) {
this.webButton = button;
}
@Override
public void render() {
// Web元素自动渲染
}
@Override
public void setText(String text) {
webButton.setText(text);
}
@Override
public String getText() {
return webButton.getText();
}
@Override
public void setEnabled(boolean enabled) {
webButton.setEnabled(enabled);
}
@Override
public void addClickListener(ClickListener listener) {
webButton.addClickHandler(e -> listener.onClick());
}
}
}
四、优缺点深度解析
优点
-
解耦客户端和适配者
- 客户端只依赖目标接口
- 适配者和客户端完全解耦
- 符合依赖倒置原则
-
复用现有类
- 可以重用现有的、功能完善的类
- 不需要修改现有代码
- 符合开闭原则
-
提高灵活性和扩展性
- 可以轻松添加新的适配器
- 支持多个适配者适配同一目标
- 支持一个适配者适配多个目标
-
简化系统架构
- 统一了不兼容的接口
- 使系统更易于理解和维护
- 降低了系统复杂度
-
支持双向适配
- 可以实现双向适配器
- 新旧系统可以互相调用
- 支持渐进式迁移
缺点
-
增加系统复杂度
- 引入了额外的类和接口
- 增加了代码的理解难度
- 可能产生过多的适配器类
-
性能开销
- 额外的间接调用带来性能损失
- 转换过程可能消耗资源
- 对性能敏感的系统需谨慎使用
-
设计过度
- 简单场景下可能过度设计
- 可能增加不必要的抽象层
- 可能使简单问题复杂化
-
适配限制
- 不是所有不兼容都能适配
- 某些语义差异难以适配
- 功能缺失无法通过适配器弥补
-
调试困难
- 调用链变长,调试困难
- 错误可能被适配器隐藏
- 难以追踪原始问题
五、使用要点与最佳实践
1. 适配器vs装饰器vs代理模式
// 模式选择指南
public class PatternSelectionGuide {
/*
* 使用适配器模式当:
* 1. 需要将不兼容接口转换为兼容接口
* 2. 需要重用现有类但其接口不匹配
* 3. 需要统一多个类的接口
*
* 使用装饰器模式当:
* 1. 需要动态添加功能
* 2. 需要透明地扩展对象功能
* 3. 需要避免子类爆炸
*
* 使用代理模式当:
* 1. 需要控制对对象的访问
* 2. 需要延迟加载或缓存
* 3. 需要添加访问控制
*/
// 示例:三种模式的对比
interface Image {
void display();
}
// 被适配者
class LegacyImage {
public void show() {
System.out.println("显示图片");
}
}
// 适配器
class ImageAdapter implements Image {
private LegacyImage legacyImage;
public ImageAdapter(LegacyImage legacyImage) {
this.legacyImage = legacyImage;
}
@Override
public void display() {
legacyImage.show(); // 适配
}
}
// 装饰器
class ImageDecorator implements Image {
protected Image decoratedImage;
public ImageDecorator(Image image) {
this.decoratedImage = image;
}
@Override
public void display() {
decoratedImage.display();
}
}
class WatermarkDecorator extends ImageDecorator {
public WatermarkDecorator(Image image) {
super(image);
}
@Override
public void display() {
super.display();
addWatermark();
}
private void addWatermark() {
System.out.println("添加水印");
}
}
// 代理
class ImageProxy implements Image {
private RealImage realImage;
private String fileName;
public ImageProxy(String fileName) {
this.fileName = fileName;
}
@Override
public void display() {
if (realImage == null) {
realImage = new RealImage(fileName); // 延迟加载
}
realImage.display();
}
}
}
2. 适配器设计模式的选择
// 类适配器 vs 对象适配器
public class AdapterTypeSelection {
/*
* 类适配器(继承):
* 优点:
* 1. 简单直接
* 2. 可以重写被适配者的方法
* 3. 只需要一个对象
*
* 缺点:
* 1. 需要多重继承(Java不支持)
* 2. 对适配者的子类不透明
* 3. 破坏封装性
*
* 对象适配器(组合):
* 优点:
* 1. 更灵活
* 2. 可以适配多个适配者
* 3. 符合组合优于继承原则
* 4. 对适配者的子类透明
*
* 缺点:
* 1. 需要额外对象
* 2. 稍微复杂
*/
// 选择建议:
// 1. 如果需要多重继承功能 -> 类适配器
// 2. 如果需要适配多个对象 -> 对象适配器
// 3. 如果需要重写行为 -> 类适配器
// 4. 如果需要更灵活的设计 -> 对象适配器
// 5. 大多数情况下 -> 使用对象适配器
}
3. 智能适配器
// 智能适配器:包含额外逻辑
public class SmartAdapterExample {
interface TemperatureSensor {
double getTemperature();
TemperatureUnit getUnit();
}
// 智能适配器
class SmartTemperatureAdapter implements TemperatureSensor {
private LegacyThermometer legacyThermometer;
private TemperatureUnit targetUnit;
private double calibrationOffset = 0.0;
private boolean useCaching = false;
private Double cachedValue = null;
private long cacheExpiry = 0;
public SmartTemperatureAdapter(LegacyThermometer thermometer, TemperatureUnit targetUnit) {
this.legacyThermometer = thermometer;
this.targetUnit = targetUnit;
}
@Override
public double getTemperature() {
if (useCaching && cachedValue != null &&
System.currentTimeMillis() < cacheExpiry) {
return cachedValue;
}
double rawValue = legacyThermometer.readValue();
// 单位转换
double convertedValue = convertUnit(rawValue,
legacyThermometer.getUnit(), targetUnit);
// 校准
double calibratedValue = convertedValue + calibrationOffset;
// 范围限制
double finalValue = clamp(calibratedValue, -100.0, 200.0);
if (useCaching) {
cachedValue = finalValue;
cacheExpiry = System.currentTimeMillis() + 1000; // 1秒缓存
}
return finalValue;
}
@Override
public TemperatureUnit getUnit() {
return targetUnit;
}
// 额外功能
public void setCalibrationOffset(double offset) {
this.calibrationOffset = offset;
}
public void enableCaching(boolean enable) {
this.useCaching = enable;
}
public void setCacheDuration(long milliseconds) {
this.cacheExpiry = System.currentTimeMillis() + milliseconds;
}
public boolean isOutOfRange() {
double temp = getTemperature();
return temp < -50.0 || temp > 100.0;
}
private double convertUnit(double value, TemperatureUnit from, TemperatureUnit to) {
if (from == to) return value;
if (from == TemperatureUnit.CELSIUS && to == TemperatureUnit.FAHRENHEIT) {
return value * 9/5 + 32;
} else if (from == TemperatureUnit.FAHRENHEIT && to == TemperatureUnit.CELSIUS) {
return (value - 32) * 5/9;
} else if (from == TemperatureUnit.KELVIN && to == TemperatureUnit.CELSIUS) {
return value - 273.15;
}
return value;
}
private double clamp(double value, double min, double max) {
return Math.max(min, Math.min(max, value));
}
}
enum TemperatureUnit {
CELSIUS, FAHRENHEIT, KELVIN
}
class LegacyThermometer {
public double readValue() {
return 25.0; // 模拟读取
}
public TemperatureUnit getUnit() {
return TemperatureUnit.CELSIUS;
}
}
}
4. 适配器注册表
// 适配器注册表:管理多个适配器
public class AdapterRegistry {
private final Map<Class<?>, Map<Class<?>, AdapterFactory<?, ?>>> registry = new HashMap<>();
public <S, T> void registerAdapter(Class<S> sourceType,
Class<T> targetType,
AdapterFactory<S, T> factory) {
registry.computeIfAbsent(sourceType, k -> new HashMap<>())
.put(targetType, factory);
}
@SuppressWarnings("unchecked")
public <S, T> T adapt(S source, Class<T> targetType) {
if (source == null) {
return null;
}
Class<?> sourceType = source.getClass();
Map<Class<?>, AdapterFactory<?, ?>> targetMap = registry.get(sourceType);
if (targetMap != null) {
AdapterFactory<S, T> factory = (AdapterFactory<S, T>) targetMap.get(targetType);
if (factory != null) {
return factory.create(source);
}
}
// 尝试查找父类适配器
for (Class<?> superType : registry.keySet()) {
if (superType.isAssignableFrom(sourceType)) {
Map<Class<?>, AdapterFactory<?, ?>> superTargetMap = registry.get(superType);
if (superTargetMap != null) {
AdapterFactory<S, T> factory = (AdapterFactory<S, T>)
superTargetMap.get(targetType);
if (factory != null) {
return factory.create(source);
}
}
}
}
throw new NoAdapterFoundException(
"No adapter found from " + sourceType + " to " + targetType);
}
public <S, T> boolean canAdapt(Class<S> sourceType, Class<T> targetType) {
if (registry.containsKey(sourceType)) {
return registry.get(sourceType).containsKey(targetType);
}
// 检查父类
for (Class<?> registeredSource : registry.keySet()) {
if (registeredSource.isAssignableFrom(sourceType)) {
if (registry.get(registeredSource).containsKey(targetType)) {
return true;
}
}
}
return false;
}
interface AdapterFactory<S, T> {
T create(S source);
}
class NoAdapterFoundException extends RuntimeException {
public NoAdapterFoundException(String message) {
super(message);
}
}
}
// 使用注册表
class RegistryExample {
public static void main(String[] args) {
AdapterRegistry registry = new AdapterRegistry();
// 注册适配器
registry.registerAdapter(LegacyUser.class, ModernUser.class,
source -> new UserAdapter(source).adapt());
registry.registerAdapter(LegacyProduct.class, ModernProduct.class,
source -> new ProductAdapter(source).adapt());
// 使用适配器
LegacyUser legacyUser = new LegacyUser("John", "Doe", 30);
ModernUser modernUser = registry.adapt(legacyUser, ModernUser.class);
System.out.println("适配后的用户: " + modernUser.getFullName());
}
}
5. 测试策略
// 适配器模式测试
public class AdapterPatternTest {
@Test
void testAdapterBasicFunctionality() {
// 测试基本适配功能
LegacyThermometer thermometer = new LegacyThermometer();
SmartTemperatureAdapter adapter = new SmartTemperatureAdapter(
thermometer, TemperatureUnit.FAHRENHEIT);
double temperature = adapter.getTemperature();
// 验证温度转换
assertTrue(temperature > 0, "温度应为正数");
assertEquals(TemperatureUnit.FAHRENHEIT, adapter.getUnit());
}
@Test
void testAdapterWithCalibration() {
// 测试带校准的适配器
LegacyThermometer thermometer = new LegacyThermometer();
SmartTemperatureAdapter adapter = new SmartTemperatureAdapter(
thermometer, TemperatureUnit.CELSIUS);
double originalTemp = adapter.getTemperature();
adapter.setCalibrationOffset(5.0);
double calibratedTemp = adapter.getTemperature();
assertEquals(originalTemp + 5.0, calibratedTemp, 0.001);
}
@Test
void testAdapterExceptionHandling() {
// 测试适配器异常处理
LegacyThermometer brokenThermometer = new BrokenThermometer();
SmartTemperatureAdapter adapter = new SmartTemperatureAdapter(
brokenThermometer, TemperatureUnit.CELSIUS);
// 应该处理异常并返回默认值
assertDoesNotThrow(() -> adapter.getTemperature());
}
@Test
void testAdapterPerformance() {
// 测试适配器性能
LegacyThermometer thermometer = new LegacyThermometer();
SmartTemperatureAdapter adapter = new SmartTemperatureAdapter(
thermometer, TemperatureUnit.FAHRENHEIT);
long startTime = System.nanoTime();
for (int i = 0; i < 10000; i++) {
adapter.getTemperature();
}
long duration = System.nanoTime() - startTime;
assertTrue(duration < 1_000_000_000, "10000次调用应在1秒内完成");
}
@Test
void testAdapterThreadSafety() throws InterruptedException {
// 测试适配器线程安全
LegacyThermometer thermometer = new LegacyThermometer();
SmartTemperatureAdapter adapter = new SmartTemperatureAdapter(
thermometer, TemperatureUnit.CELSIUS);
int threadCount = 10;
ExecutorService executor = Executors.newFixedThreadPool(threadCount);
List<Future<Double>> results = new ArrayList<>();
for (int i = 0; i < threadCount; i++) {
results.add(executor.submit(adapter::getTemperature));
}
for (Future<Double> result : results) {
assertDoesNotThrow(result::get);
}
executor.shutdown();
assertTrue(executor.awaitTermination(5, TimeUnit.SECONDS));
}
@Test
void testAdapterRegistry() {
// 测试适配器注册表
AdapterRegistry registry = new AdapterRegistry();
registry.registerAdapter(LegacyUser.class, ModernUser.class,
legacy -> new UserAdapter(legacy).adapt());
LegacyUser legacyUser = new LegacyUser("Alice", "Smith", 25);
ModernUser modernUser = registry.adapt(legacyUser, ModernUser.class);
assertNotNull(modernUser);
assertEquals("Alice Smith", modernUser.getFullName());
// 测试不支持的转换
assertThrows(NoAdapterFoundException.class, () -> {
registry.adapt(legacyUser, String.class);
});
}
// 测试辅助类
class BrokenThermometer extends LegacyThermometer {
@Override
public double readValue() {
throw new RuntimeException("传感器故障");
}
}
}
六、与其他模式的比较
| 模式 | 相似点 | 不同点 | 适用场景 |
|---|---|---|---|
| 装饰器模式 | 都包装对象 | 装饰器增强功能,适配器转换接口 | 需要功能扩展用装饰器,需要接口转换用适配器 |
| 代理模式 | 都包装对象 | 代理控制访问,适配器转换接口 | 需要访问控制用代理,需要接口转换用适配器 |
| 外观模式 | 都简化接口 | 外观简化子系统接口,适配器转换单个接口 | 简化复杂子系统用外观,转换不兼容接口用适配器 |
| 桥接模式 | 都解耦抽象和实现 | 桥接分离抽象和实现,适配器使不兼容接口协同工作 | 多维度变化用桥接,接口不兼容用适配器 |
七、实际应用示例
示例1:Java标准库中的适配器
// Java标准库中的适配器模式
public class JavaStandardLibraryAdapters {
public static void main(String[] args) {
// 1. InputStreamReader/OutputStreamWriter
// 将字节流适配为字符流
try (InputStreamReader reader =
new InputStreamReader(System.in)) {
// 字节流 -> 字符流
}
// 2. Arrays.asList() - 数组到List的适配器
String[] array = {"a", "b", "c"};
List<String> list = Arrays.asList(array);
// 3. Collections.unmodifiableXXX() - 只读适配器
List<String> modifiable = new ArrayList<>();
List<String> unmodifiable = Collections.unmodifiableList(modifiable);
// 4. Enumeration -> Iterator适配器
Vector<String> vector = new Vector<>();
Enumeration<String> enumeration = vector.elements();
Iterator<String> iterator = new EnumerationIterator<>(enumeration);
// 5. Runnable适配器
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("运行中");
}
});
// 6. TimerTask适配器
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
System.out.println("定时任务");
}
}, 1000);
}
// Enumeration到Iterator的适配器
static class EnumerationIterator<E> implements Iterator<E> {
private final Enumeration<E> enumeration;
public EnumerationIterator(Enumeration<E> enumeration) {
this.enumeration = enumeration;
}
@Override
public boolean hasNext() {
return enumeration.hasMoreElements();
}
@Override
public E next() {
return enumeration.nextElement();
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
}
示例2:Spring框架中的适配器
// Spring框架中的适配器模式
@Configuration
public class SpringAdaptersExample {
// 1. HandlerAdapter - 处理各种Handler
@Bean
public HandlerAdapter handlerAdapter() {
return new SimpleControllerHandlerAdapter();
}
// 2. MessageConverter - 消息转换适配器
@Bean
public HttpMessageConverter<String> stringMessageConverter() {
return new StringHttpMessageConverter();
}
// 3. WebMvcConfigurer适配器
@Bean
public WebMvcConfigurer webMvcConfigurer() {
return new WebMvcConfigurerAdapter() {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/home").setViewName("home");
}
};
}
// 4. 事件监听器适配器
@Bean
public ApplicationListener<ContextRefreshedEvent> contextRefreshedListener() {
return new ApplicationListenerAdapter() {
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
System.out.println("应用上下文已刷新");
}
};
}
// 5. 属性编辑器适配器
@Bean
public CustomEditorConfigurer customEditorConfigurer() {
CustomEditorConfigurer configurer = new CustomEditorConfigurer();
Map<Class<?>, Class<? extends PropertyEditor>> editors = new HashMap<>();
editors.put(Date.class, CustomDateEditor.class);
configurer.setCustomEditors(editors);
return configurer;
}
}
// 自定义适配器示例
@Component
public class LegacyServiceAdapter implements ModernService {
private final LegacyService legacyService;
public LegacyServiceAdapter(LegacyService legacyService) {
this.legacyService = legacyService;
}
@Override
public ModernResult process(ModernRequest request) {
// 转换请求
LegacyRequest legacyRequest = convertRequest(request);
// 调用遗留服务
LegacyResult legacyResult = legacyService.processLegacy(legacyRequest);
// 转换结果
return convertResult(legacyResult);
}
private LegacyRequest convertRequest(ModernRequest request) {
// 转换逻辑
return new LegacyRequest();
}
private ModernResult convertResult(LegacyResult result) {
// 转换逻辑
return new ModernResult();
}
}
八、注意事项
- 避免过度使用:不要为每个接口不匹配都创建适配器
- 保持适配器简单:适配器应专注于接口转换,避免复杂业务逻辑
- 考虑性能影响:频繁调用的适配器需要考虑性能优化
- 处理异常:适配器应妥善处理转换过程中的异常
- 保持透明性:适配器应对客户端透明
- 文档化转换规则:明确记录接口转换规则
- 测试适配器:充分测试适配器的各种转换场景
- 考虑双向适配:如果需要双向交互,考虑实现双向适配器
- 避免适配器链:避免多层适配器嵌套,增加复杂性
- 使用合适模式:根据场景选择类适配器或对象适配器
九、总结
适配器模式是一种强大的结构型模式,特别适用于:
- 集成遗留系统
- 使用第三方库
- 统一多个接口
- 支持多种实现
适配器模式的核心价值:
- 解耦:将客户端与具体实现解耦
- 复用:重用现有代码,无需修改
- 灵活:支持多种适配方式
- 渐进:支持系统渐进式重构
最佳实践建议:
- 优先使用对象适配器:更灵活,符合组合优于继承原则
- 保持适配器单一职责:一个适配器只负责一种转换
- 添加适当日志:便于调试转换过程
- 考虑性能优化:对频繁调用的适配器进行优化
- 充分测试:测试各种边界情况和异常场景
- 文档化:明确记录适配器的转换规则和限制
适配器模式是处理系统集成、技术升级和多平台支持的必备工具。正确使用适配器模式可以显著提高系统的灵活性、可维护性和可扩展性。