擴充卡模式的意圖 : 使用不同接口的類所提供的服務為用戶端提供其所希望的接口;
-- 問題解決場景 : 在 類a 中實作了接口中的抽象方法, 用戶端b 已經定義好了方法的調用, 但是調用的方法 與 類a 中的方法名不同, 這時我們就需要擴充卡模式了;
-- eg : 類a 實作了接口a1, 類b 實作了接口b1, 這裡c調用 a 和 b 希望 a 和 b 能提供相同方法的接口, 這時我們需要使用擴充卡模式;
接口适配 :
-- 問題場景 : 用戶端需要調用 用戶端類接口 中提供的 requiredmethod()的方法, 但是工具類中隻提供了一個 existmethod() 方法, 顯然用戶端接口 與 工具類中提供的方法名稱不比對;
-- 适配方案 : 建立一個 擴充卡類, 适配現有的代碼 工具類, 該類實作用戶端接口的 requiredmethod()抽象方法,
與用戶端接口是實作關系, 同時該實作類繼承 工具類, 可以調用工具類中的方法, 與工具類的關系是 繼承關系;
-- 方法委托 : 通過接口适配, 就将 用戶端類的requiredmethod() 方法 委派給了 existmethod()方法;
.
接口适配需求 :
-- 用戶端提供接口 : 需要研發一種m1坦克, 需要實作接口 getcaliber() 擷取火炮口徑, fire() 開火, run()移動 等方法;
-- 現有接口 : 現有的坦克 有 getguncaliber() 擷取火炮口徑, gunfire() 火炮開火, move() 移動 等方法;
-- 适配要求 : 寫一個适配類, 這個類實作 panzer 接口, 繼承 tanker 類,
将panzer接口的動作委托給 tanker 類;
接口類 :
[java] view
plaincopy
package shuliang.han.displaytest;
public interface panzer {
public double getcaliber();
public void fire();
public void run();
}
實體類 :
public class tanker {
private double caliber = 125.0;
public double getguncaliber() {
return caliber;
}
public void gunfire() {
system.out.println("fire in the hole !!!");
public void move() {
system.out.println("move move !!");
分析 :
-- 名稱不比對 : tanker類中的方法可以執行 panzer 接口中需要的動作, 但是它們的方法名稱不比對;
-- 變量維護 : 如果建立一個 m1a2sep 類, 需要在類中維護一個 tank 對象, 在 panzer 實作類中調用 對應的 tank 對象方法;
m1a2sep 類 :
public class m1a2sep extends tanker implements panzer {
@override
public double getcaliber() {
return getguncaliber();
public void fire() {
gunfire();
public void run() {
move();
接口适配總結 :
-- 用戶端接口存在 : 如果用戶端接口中定義了用戶端所期待的行為, 可以運用擴充卡模式, 擴充卡繼承現有類, 并實作用戶端接口;
-- 用戶端接口不存在 : 如果用戶端沒有定義接口, 可以使用對象擴充卡, 對象擴充卡相當于 子類擴充卡;
類适配 : 上面的接口适配方式就是類适配, 擴充卡類需要 實作用戶端接口, 繼承 現有實體類;
對象适配 : 對象擴充卡采用了委派, 并非是繼承; 建立一個對象擴充卡, 繼承用戶端類,
在類中維護一個現有類執行個體對象, 滿足用戶端類需求方法;
-- 需要場景 : 如果适配的用戶端方法沒有被定義在接口中, 就需要對象适配;
對象适配的方法 :
-- 擴充卡類繼承用戶端類 : 對象适配的擴充卡類 繼承用戶端類對象, 擴充卡類 的 執行個體 也是 用戶端類的執行個體, 因為擴充卡類是用戶端類的子類;
-- 擴充卡類使用現有類 : 擴充卡類中定義一個 現有類對象作為成員變量, 通過調用 現有類對象中的方法 來實作用戶端類方法的需求;
用戶端類 : 現在有用戶端類 panzer 裝甲車, 提供 擷取火炮口徑方法 getcaliber(), 移動方法 run(), 開火方法 fire();
現有類 : 現有類 tank 坦克, 提供 擷取火炮口徑方法 getguncaliber(), 移動方法 move(), 開火方法 gunfire();
用戶端類代碼 : 用戶端類代碼中沒有指定模組化所需的接口;
package shuliang.han.adapter;
public class panzer {
public double getcaliber(){
return 0;
public void fire(){
//todo
public void run(){
現有類代碼 :
public class tank {
public double getguncaliber(){
system.out.println("move move !!!");
uml圖 :
擴充卡類 :
public class m1a2 extends panzer {
private tank tank;
public m1a2() {
tank = new tank();
return tank.getguncaliber();
super.fire();
tank.gunfire();
super.run();
tank.move();
對象适配比類适配要脆弱 :
-- 沒有規範接口 : 對象适配的類中沒有規範的接口, 如果用戶端類出現了變化,
運作時可能出現錯誤;
-- 用戶端類不可預知 : 對象适配類 繼承用戶端類, 首先用戶端類需要将方法 和 變量聲明為 protected, 即使這樣, 這些類的方法也可能不符合子類意圖;
jtable适配資料方法 : jtable類可以将實作了tablemodel抽象類的資料顯示到圖形界面中;
-- 資料不确定性 : java中的swing 提供了jtable控件用以顯示清單, jtable不知道我們要顯示什麼資料;
-- 擴充卡 : 将資料交給jtable控件并顯示出來, 需要一個擴充卡, 這些資料要經過一個擴充卡接口, 這個接口是 tablemodel 抽象類;
tablemodel子類實作 :
-- 抽象方法多 : jtable定義了許多抽象方法, 其子類必須實作所有的抽象方法, 這樣會很麻煩;
-- tablemodel的樁 : jdk中提供了另一個抽象類 abstracttablemodel 類, abstracttablemodel 繼承了 tablemodel 類, 并實作了絕大部分方法,
我們可以定義一個類 去 繼承 abstracttablemodel 類, 并實作我們感興趣的方法, 不必實作所有的方法了;
-- 資料封裝 : 建立一個類 繼承 abstracttablemodel 類, 然後呢實作感興趣的接口;
實作過程 : 使用jtable 繪制坦克相關資料, 需要建立一個tanktablemodel類 繼承 abstracttablemodel 類, 然後将 tank 類封裝在 tanktablemodel
中, 當做其成員變量;
使用對象适配的原因 :
-- abstracttablemodel 抽象類 : 該抽象類提供了擴充卡對象需要實作的接口 (抽象方法), 該抽象類又實作了用戶端 jtable類 期待的接口,
擴充卡對象必須繼承抽象類;
-- 組合第三對象 : 擴充卡對象還需要重用第三個對象, 重用對象的方法隻能是
繼承 和 組合, java是單繼承機制, 隻能使用組合方式, 即将第三個對象當做擴充卡類的成員變量;
tank代碼 :
package shuliang.han.jtable;
private double caliber;
private double speed;
private string name;
public tank(double caliber, double speed, string name) {
this.caliber = caliber;
this.speed = speed;
this.name = name;
public double getspeed() {
return speed;
public string getname() {
return name;
tanktablemodel代碼 :
import javax.swing.table.abstracttablemodel;
public class tanktablemodel extends abstracttablemodel {
private tank tanks[];
private string names[];
public tanktablemodel(tank[] tanks, string[] names) {
this.tanks = tanks;
this.names = names;
public int getrowcount() {
return tanks.length;
public int getcolumncount() {
return names.length;
public string getcolumnname(int column) {
return names[column];
public object getvalueat(int rowindex, int columnindex) {
switch(columnindex){
case 0 :
return tanks[rowindex].getname();
case 1 :
return new double(tanks[rowindex].getcaliber());
case 2 :
return new double(tanks[rowindex].getspeed());
default :
return null;
}
showtankdata代碼 :
import java.awt.component;
import java.awt.dimension;
import java.awt.font;
import javax.swing.jframe;
import javax.swing.jscrollpane;
import javax.swing.jtable;
import javax.swing.uimanager;
public class showtanksdata {
public static void main(string[] args) {
setframe();
jtable jtable = new jtable(gettanktablemodel());
jtable.setrowheight(36);
jscrollpane pane = new jscrollpane(jtable);
pane.setpreferredsize(new dimension(300, 100));
display(pane, "坦克資料");
private static void setframe() {
font font = new font("dialog", font.plain, 18);
uimanager.put("table.font", font);
uimanager.put("tableheader.font", font);
private static tanktablemodel gettanktablemodel() {
tank tank1 = new tank(120.0, 50.0, "99式");
tank tank2 = new tank(150.0, 2.0, "kv");
return new tanktablemodel(new tank[]{tank1, tank2}, new string[]{"名稱", "火炮口徑 ", "速度"});
private static void display(component component, string tittle) {
jframe frame = new jframe(tittle);
frame.getcontentpane().add(component);
frame.setdefaultcloseoperation(jframe.exit_on_close);
frame.pack();
frame.setvisible(true);
效果圖 :
mouseadapter 為 mouselistener 接口提供樁的實作;
在使用mouseadapter的時候, 就相當于使用了擴充卡 : 使用者操作滑鼠的時候, 将swing元件接收到的滑鼠操作适配給相應的動作處理類中,
即将gui時間适配給應用程式接口, 使用了swing适配類, 将一個接口方法委派給一個類的方法去執行;
擴充卡總結 : 擴充卡模式可以重用一個現有類, 滿足用戶端需求, 将用戶端的調用轉化為現有方法的調用;
-- 類擴充卡 : 用戶端的需求通過接口表達出來, 可以建立一個實作了該接口的适配類, 适配類同時還要繼承現有類;
-- 對象适配 : 用戶端沒有指定接口, 建立一個新擴充卡類, 實作 繼承用戶端類, 在該類中維護一個現有類的執行個體對象作為成員變量;
jtable擴充卡模式 : 通過定義tablemodel接口, jtable元件将用戶端需要的表資訊存儲到自身中, 通過自定義擴充卡對象, 将任何資料适配到表中;
jtable不适用類适配原因 :
-- 繼承數量限制 : jtable擴充卡需要繼承 abstracttablemodel類, 這樣就無法繼承現有類, 因為隻能繼承一個類;
-- 需要維護多個對象 : jtable需要大量資料, 一般是從多個對象中采集的;
設計擴充卡模式 : 當我們設計軟體的時候, 充分考慮程式的靈活性, jtable 的設計就是一個很好的範例;