.java
做者 :萬境絕塵 ide
轉載請註明出處 : http://blog.csdn.net/shulianghan/article/details/19077139工具
.ui
適配器模式的意圖 : 使用不一樣接口的類所提供的服務爲客戶端提供其所但願的接口;this
-- 問題解決場景 : 在 類A 中實現了接口中的抽象方法, 客戶端B 已經定義好了方法的調用, 可是調用的方法 與 類A 中的方法名不一樣, 這時咱們就須要適配器模式了;spa
-- eg : 類A 實現了接口A1, 類B 實現了接口B1, 這裏C調用 A 和 B 但願 A 和 B 能提供相同方法的接口, 這時咱們須要使用適配器模式;.net
接口適配 : 設計
-- 問題場景 : 客戶端須要調用 客戶端類接口 中提供的 requiredMethod()的方法, 可是工具類中只提供了一個 existMethod() 方法, 顯然客戶端接口 與 工具類中提供的方法名稱不匹配;code
-- 適配方案 : 建立一個 適配器類, 適配現有的代碼 工具類, 該類實現客戶端接口的 requiredMethod()抽象方法, 與客戶端接口是實現關係, 同時該實現類繼承 工具類, 能夠調用工具類中的方法, 與工具類的關係是 繼承關係;component
-- 方法委託 : 經過接口適配, 就將 客戶端類的requiredMethod() 方法 委派給了 existMethod()方法;
.
接口適配需求 :
-- 客戶端提供接口 : 須要研發一種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 { @Override public double getCaliber() { return getGunCaliber(); } @Override public void fire() { gunFire(); } @Override 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(){ //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(); } @Override public double getCaliber() { return tank.getGunCaliber(); } @Override public void fire() { super.fire(); tank.gunFire(); } @Override public void run() { 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是單繼承機制, 只能使用組合方式, 即將第三個對象當作適配器類的成員變量;
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; } @Override public int getRowCount() { return tanks.length; } @Override public int getColumnCount() { return names.length; } @Override public String getColumnName(int column) { return names[column]; } @Override 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; } } }
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); } }
效果圖 :
MouseAdapter 爲 MouseListener 接口提供樁的實現;
在使用MouseAdapter的時候, 就至關於使用了適配器 : 用戶操做鼠標的時候, 將swing組件接收到的鼠標操做適配給相應的動做處理類中, 即將GUI時間適配給應用程序接口, 使用了Swing適配類, 將一個接口方法委派給一個類的方法去執行;
適配器總結 : 適配器模式能夠重用一個現有類, 知足客戶端需求, 將客戶端的調用轉化爲現有方法的調用;
-- 類適配器 : 客戶端的需求經過接口表達出來, 能夠建立一個實現了該接口的適配類, 適配類同時還要繼承現有類;
-- 對象適配 : 客戶端沒有指定接口, 建立一個新適配器類, 實現 繼承客戶端類, 在該類中維護一個現有類的實例對象做爲成員變量;
JTable適配器模式 : 經過定義TableModel接口, JTable組件將客戶端須要的表信息存儲到自身中, 經過自定義適配器對象, 將任何數據適配到表中;
JTable不適用類適配緣由 :
-- 繼承數量限制 : JTable適配器須要繼承 AbstractTableModel類, 這樣就沒法繼承現有類, 由於只能繼承一個類;
-- 須要維護多個對象 : JTable須要大量數據, 通常是從多個對象中採集的;
設計適配器模式 : 當咱們設計軟件的時候, 充分考慮程序的靈活性, JTable 的設計就是一個很好的範例;
.
做者 :萬境絕塵
轉載請註明出處 : http://blog.csdn.net/shulianghan/article/details/19077139
.