在開發中常遇到這種情況:有兩個現成的類,它們之間毫無關聯,但我們想同時使用它們的方法。修改原有介面雖可行,卻違背「開閉原則」,維護成本高。適配器模式(Adapter Pattern)作為 GoF 23 種設計模式中的結構型模式,正是為了解決此類問題而生——它能將既有類的介面轉換為客戶端期望的介面,使原本不相容的類能夠協同工作。
透過繼承被適配類並實現目標介面來達成適配。屬於靜態定義,編譯期確定。
// 被適配者:會畫矩形
public class DrawRectangle {
public void drawRectangle(String msg) {
System.out.println("draw Rectangle: " + msg);
}
}
// 目標介面:會畫圓形
public interface IDrawCircle {
void drawCircle();
}
// 類適配器:繼承 DrawRectangle、實現 IDrawCircle
public class DrawAdapter4Class extends DrawRectangle implements IDrawCircle {
@Override
public void drawCircle() {
System.out.println("DrawAdapter4Class: drawCircle");
}
}
採用組合方式,持有被適配者的引用,並實現目標介面。較具彈性,可適配子類。
public class DrawAdapter4Object implements IDrawCircle {
private DrawRectangle drawRectangle; // 組合被適配者
public DrawAdapter4Object(DrawRectangle drawRectangle) {
this.drawRectangle = drawRectangle;
}
@Override
public void drawCircle() {
System.out.println("DrawAdapter4Object: drawcircle");
}
// 代理被適配者的方法
public void drawRectangle(String msg) {
drawRectangle.drawRectangle(msg);
}
}
當介面方法過多,但我們只需實現其中幾個時,可提供一個預設空實現的抽象類,子類只需覆寫需要的方法。
// 含多個方法的介面
public interface IDraw {
void drawCircle();
void drawRectangle();
}
// 預設空實現適配器
public class DefaultDrawAdapter implements IDraw {
@Override public void drawCircle() {}
@Override public void drawRectangle() {}
}
// 具體實現:只關心畫圓
public class MyDrawAdapter extends DefaultDrawAdapter {
@Override
public void drawCircle() {
System.out.println("drawCircle in MyDrawAdapter");
}
}
public class Test {
public static void main(String[] args) {
// 物件適配器
DrawAdapter4Object objAdapter = new DrawAdapter4Object(new DrawRectangle());
objAdapter.drawCircle();
objAdapter.drawRectangle(" in DrawAdapter4Object");
System.out.println("--------------");
// 類適配器
DrawAdapter4Class clzAdapter = new DrawAdapter4Class();
clzAdapter.drawCircle();
clzAdapter.drawRectangle("in DrawAdapter4Class");
System.out.println("--------------");
// 介面適配器
MyDrawAdapter myDrawAdapter = new MyDrawAdapter();
myDrawAdapter.drawCircle();
myDrawAdapter.drawRectangle();
}
}
輸出結果:
DrawAdapter4Object: drawcircle draw Rectangle: in DrawAdapter4Object -------------- DrawAdapter4Class: drawCircle draw Rectangle: in DrawAdapter4Class -------------- drawCircle in MyDrawAdapter
設計模式非為用而用,而應從實際設計問題出發,看哪個模式能解決問題。熟練掌握 SOLID 等設計原則,模式自會水到渠成。