日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

【面向对象设计模式】 适配器模式 (二)

發布時間:2025/6/17 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【面向对象设计模式】 适配器模式 (二) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

.

作者?:萬境絕塵?

轉載請注明出處?:?http://blog.csdn.net/shulianghan/article/details/19077139

.



適配器模式的意圖 : 使用不同接口的類所提供的服務為客戶端提供其所希望的接口;

--?問題解決場景?: 在 類A 中實現了接口中的抽象方法, 客戶端B 已經定義好了方法的調用, 但是調用的方法 與 類A 中的方法名不同, 這時我們就需要適配器模式了;

-- eg : 類A 實現了接口A1, 類B 實現了接口B1, 這里C調用 A 和 B 希望 A 和 B 能提供相同方法的接口, 這時我們需要使用適配器模式;



1. 接口適配



(1) 接口適配簡介


接口適配 :?

-- 問題場景 : 客戶端需要調用 客戶端類接口 中提供的 requiredMethod()的方法, 但是工具類中只提供了一個 existMethod() 方法, 顯然客戶端接口 與 工具類中提供的方法名稱不匹配;

-- 適配方案 : ?創建一個 適配器類, 適配現有的代碼 工具類, ?該類實現客戶端接口的 requiredMethod()抽象方法, 與客戶端接口是實現關系, 同時該實現類繼承 工具類, 可以調用工具類中的方法,?與工具類的關系是 繼承關系;

-- 方法委托 : 通過接口適配, 就將 客戶端類的requiredMethod() 方法 委派給了 existMethod()方法;





(2) 接口適配實例


.

接口適配需求 :?

-- 客戶端提供接口 : 需要研發一種M1坦克, 需要實現接口 getCaliber() 獲取火炮口徑, fire() 開火, run()移動 等方法;?

-- 現有接口 : 現有的坦克 有 getGunCaliber() 獲取火炮口徑, GunFire() 火炮開火, Move() 移動 等方法;

-- 適配要求 : 寫一個適配類, 這個類實現 Panzer 接口, 繼承 Tanker 類, 將Panzer接口的動作委托給 Tanker 類;





接口類 :?

package shuliang.han.displaytest;public interface Panzer {public double getCaliber();public void fire();public void run();}
實體類 :?

package shuliang.han.displaytest;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 類 :?

package shuliang.han.displaytest;public class M1A2SEP extends Tanker implements Panzer {@Overridepublic double getCaliber() {return getGunCaliber();}@Overridepublic void fire() {gunFire();}@Overridepublic void run() {move();}}


接口適配總結 :?

-- 客戶端接口存在 : 如果客戶端接口中定義了客戶端所期待的行為, 可以運用適配器模式, 適配器繼承現有類, 并實現客戶端接口;

-- 客戶端接口不存在 : 如果客戶端沒有定義接口, 可以使用對象適配器, 對象適配器相當于 子類適配器;



2. 對象適配


(1) 對象適配簡介


類適配 : 上面的接口適配方式就是類適配, 適配器類需要 實現客戶端接口, 繼承 現有實體類;

對象適配 : 對象適配器采用了委派, 并非是繼承; 創建一個對象適配器, 繼承客戶端類, 在類中維護一個現有類實例對象, 滿足客戶端類需求方法;?

-- 需要場景 : 如果適配的客戶端方法沒有被定義在接口中, 就需要對象適配;




對象適配的方法 :?

-- 適配器類繼承客戶端類 : 對象適配的適配器類 繼承客戶端類對象, 適配器類 的 實例 也是 客戶端類的實例, 因為適配器類是客戶端類的子類; ?

-- 適配器類使用現有類 : 適配器類中定義一個 現有類對象作為成員變量, 通過調用 現有類對象中的方法 來實現客戶端類方法的需求;


(2) 對象適配實例


客戶端類 : 現在有客戶端類 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(){//TODO} }
現有類代碼 :?

package shuliang.han.adapter;public class Tank {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 !!!");} }

UML圖 :?



適配器類 :?

package shuliang.han.adapter;public class M1A2 extends Panzer {private Tank tank;public M1A2() {tank = new Tank();}@Overridepublic double getCaliber() {return tank.getGunCaliber();}@Overridepublic void fire() {super.fire();tank.gunFire();}@Overridepublic void run() {super.run();tank.move();}}


(3) 脆弱的對象適配


對象適配比類適配要脆弱 :?

-- 沒有規范接口 : 對象適配的類中沒有規范的接口, 如果客戶端類出現了變化, 運行時可能出現錯誤;

-- 客戶端類不可預知 : 對象適配類 繼承客戶端類, 首先客戶端類需要將方法 和 變量聲明為 protected, 即使這樣, 這些類的方法也可能不符合子類意圖;



3. Jtable 對數據適配


(1) Jtable 與 TableModel AbstractTableModel模型?


JTable適配數據方法 : JTable類可以將實現了TableModel抽象類的數據顯示到圖形界面中;

-- 數據不確定性 : Java中的Swing 提供了JTable控件用以顯示列表, JTable不知道我們要顯示什么數據;?

-- 適配器 : 將數據交給JTable控件并顯示出來, 需要一個適配器, 這些數據要經過一個適配器接口, 這個接口是 TableModel 抽象類;


TableModel子類實現 :?

-- 抽象方法多 : Jtable定義了許多抽象方法, 其子類必須實現所有的抽象方法, 這樣會很麻煩;?

-- TableModel的樁 : JDK中提供了另一個抽象類 AbstractTableModel 類, AbstractTableModel 繼承了 TableModel 類, 并實現了絕大部分方法, 我們可以定義一個類 去 繼承 AbstractTableModel 類, 并實現我們感興趣的方法, 不必實現所有的方法了;

-- 數據封裝 : 創建一個類 繼承 AbstractTableModel 類, 然后呢實現感興趣的接口;



(2) 實例


實現過程 : 使用JTable 繪制坦克相關數據, 需要創建一個TankTableModel類 繼承 AbstractTableModel 類, 然后將 Tank 類封裝在 TankTableModel 中, 當做其成員變量;


使用對象適配的原因 :?

--?AbstractTableModel 抽象類 : 該抽象類提供了適配器對象需要實現的接口 (抽象方法), 該抽象類又實現了客戶端 JTable類 期待的接口, 適配器對象必須繼承抽象類;

--?組合第三對象 : 適配器對象還需要重用第三個對象, 重用對象的方法只能是 繼承 和 組合, Java是單繼承機制, 只能使用組合方式, 即將第三個對象當做適配器類的成員變量;


UML圖 :?



Tank代碼 :?

package shuliang.han.jtable;public class Tank {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 getCaliber() {return caliber;}public double getSpeed() {return speed;}public String getName() {return name;}}


TankTableModel代碼 :?

package shuliang.han.jtable;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;}@Overridepublic int getRowCount() {return tanks.length;}@Overridepublic int getColumnCount() {return names.length;}@Overridepublic String getColumnName(int column) {return names[column];}@Overridepublic 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代碼 :?

package shuliang.han.jtable;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);}}

效果圖 :?




4. 識別適配器



MouseAdapter 為 MouseListener 接口提供樁的實現;



在使用MouseAdapter的時候, 就相當于使用了適配器 :?用戶操作鼠標的時候, 將swing組件接收到的鼠標操作適配給相應的動作處理類中, 即將GUI時間適配給應用程序接口, 使用了Swing適配類, 將一個接口方法委派給一個類的方法去執行;



5. 適配器模式總結


適配器總結 : 適配器模式可以重用一個現有類, 滿足客戶端需求, 將客戶端的調用轉化為現有方法的調用;

-- 類適配器 : 客戶端的需求通過接口表達出來, 可以創建一個實現了該接口的適配類, 適配類同時還要繼承現有類;

-- 對象適配 : 客戶端沒有指定接口, 創建一個新適配器類, 實現 繼承客戶端類, 在該類中維護一個現有類的實例對象作為成員變量;


JTable適配器模式 : 通過定義TableModel接口, JTable組件將客戶端需要的表信息存儲到自身中, 通過自定義適配器對象, 將任何數據適配到表中;


JTable不適用類適配原因 :?

-- 繼承數量限制 : JTable適配器需要繼承 AbstractTableModel類, 這樣就無法繼承現有類, 因為只能繼承一個類;

-- 需要維護多個對象 : JTable需要大量數據, 一般是從多個對象中采集的;


設計適配器模式 : 當我們設計軟件的時候, 充分考慮程序的靈活性, JTable 的設計就是一個很好的范例;


.

作者?:萬境絕塵?

轉載請注明出處 :?http://blog.csdn.net/shulianghan/article/details/19077139

.

總結

以上是生活随笔為你收集整理的【面向对象设计模式】 适配器模式 (二)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。