適配器模式是結構型模式中的經典之作,核心目的是將一個類的介面轉換為客戶端期望的另一個介面,使原本介面不兼容的類能夠協同工作。本文系統梳理適配器模式的類適配器(繼承式)與物件適配器(組合式)兩種形式,並通過 JDK 內建案例、幾何圖形轉換、寵物適配等生動範例,全方位剖析其實現細節與選型策略。
| 角色 | 說明 | 類適配器 | 物件適配器 |
|---|---|---|---|
| Target(目標介面) | 客戶端期望的介面 | 介面 | 介面或抽象類 |
| Adaptee(被適配者) | 現有、需適配的類 | 類(被繼承) | 類(被組合) |
| Adapter(適配器) | 核心轉換邏輯 | 繼承 Adaptee + 實作 Target | 組合 Adaptee + 實作 Target |

package com.javapatterns.adapter.classAdapter;
public interface Target {
void sampleOperation1(); // Adaptee 已有
void sampleOperation2(); // Adaptee 缺失
}
public class Adaptee {
public void sampleOperation1() { /* 現有實現 */ }
}
public class Adapter extends Adaptee implements Target {
@Override
public void sampleOperation2() {
// 補充實現缺失的操作
}
}

package com.javapatterns.adapter;
public class Adapter implements Target {
private final Adaptee adaptee;
public Adapter(Adaptee adaptee) {
this.adaptee = adaptee;
}
@Override
public void sampleOperation1() {
adaptee.sampleOperation1(); // 委派
}
@Override
public void sampleOperation2() {
// 補充實現
}
}
java.awt.event 套件提供大量適配器類:
WindowAdapter、MouseAdapter、KeyAdapter 等設計精髓:
// WindowListener 介面有 7 個方法
public interface WindowListener {
void windowOpened(WindowEvent e);
void windowClosing(WindowEvent e);
// ... 共 7 個方法
}
// WindowAdapter 抽象類提供所有方法的空實現
public abstract class WindowAdapter implements WindowListener {
public void windowOpened(WindowEvent e) {}
public void windowClosing(WindowEvent e) {}
// ... 全部空實現
}
使用方式:匿名內部類僅覆寫關心的方法
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
此處目標介面與來源介面相同,適配器的作用是免除實作所有方法的負擔——這是適配器模式的變體應用。

現有 Cube 類(立方體),客戶端期望 BallIF 介面(球體),需計算表面積、體積、半徑。
package com.javapatterns.adapter.cube2ball;
public class Cube {
private double width;
public Cube(double width) { this.width = width; }
public double calculateVolume() { return width * width * width; }
public double getWidth() { return width; }
}
public interface BallIF {
double calculateArea(); // 表面積
double calculateVolume(); // 體積
double getRadius(); // 半徑
void setRadius(double radius);
}
public class MagicFinger implements BallIF {
private final Cube adaptee;
private double radius;
private static final double PI = 3.14;
public MagicFinger(Cube adaptee) {
this.adaptee = adaptee;
this.radius = adaptee.getWidth(); // 內切球半徑 = 立方體邊長
}
@Override public double calculateArea() {
return 4 * PI * radius * radius;
}
@Override public double calculateVolume() {
return 4.0/3.0 * PI * radius * radius * radius;
}
@Override public double getRadius() { return radius; }
@Override public void setRadius(double radius) { this.radius = radius; }
}
數學含義:將立方體轉換為其內切球(最大能放入立方體的球)。
為何選物件適配器? 未來若新增 Tetrahedron(四面體)、Octahedron(八面體)等多面體,同一個 MagicFinger 類即可適配,無需為每種形狀建立專屬適配器類。
| 變體 | 描述 | 適用場景 |
|---|---|---|
| 目標介面省略 | Target 與 Adaptee 介面相同,適配器僅提供預設實現 | 事件監聽器適配器 |
| 抽象適配器類 | Adapter 為 abstract class,提供部分預設實現 | 需共享邏輯的適配器家族 |
| 參數化適配器 | 適配器根據建構參數返回不同適配實例 | 適配器非 Adaptee 子類、需動態選擇 |
if (需適配 Adaptee 及其子類族) → 物件適配器
else if (需覆寫 Adaptee 核心行為) → 類適配器
else if (目標介面與來源介面相同) → 目標介面省略變體(如 WindowAdapter)
else if (適配邏輯極簡、無狀態) → 考慮靜態工廠方法替代
else → 物件適配器(預設首選,符合組合優於繼承)
Boyfriend extends Kittie implements Doggie)適配器模式是「介面不匹配」問題的標準解法。物件適配器因其鬆耦合、支援子類族、符合組合復用原則,應為預設首選;類適配器適用於需覆寫被適配者行為、且確定無子類擴展需求的場景。JDK 中的 WindowAdapter 則展示了「目標介面省略」這一實用變體。掌握這些變體與選型邏輯,能讓你在面對遺留系統整合、第三方庫適配、微服務介面轉換等場景時遊刃有餘。