舉個慄子 問題描述 不同國家的人在NBA打球,但都是用英文交流。 簡單實現 Player Forwards Center Guards 測試 測試結果 存在問題 姚明剛到NBA時可能英文還不太好,也就是說聽不懂教練的戰術安排,attach 和 defense 不知道什麼意思,因此這樣實現會有問題,需 ...
舉個慄子
問題描述
不同國家的人在NBA打球,但都是用英文交流。
簡單實現
Player
/**
* 球員
* Created by callmeDevil on 2019/8/4.
*/
public abstract class Player {
protected String name;
public Player(String name){
this.name = name;
}
// 發起進攻
public abstract void attack();
// 轉回防守
public abstract void defense();
}
Forwards
/**
* 前鋒
* Created by callmeDevil on 2019/8/4.
*/
public class Forwards extends Player {
public Forwards(String name){
super(name);
}
@Override
public void attack() {
System.out.println(String.format("前鋒 %s 進攻", name));
}
@Override
public void defense() {
System.out.println(String.format("前鋒 %s 防守", name));
}
}
Center
/**
* 中鋒
* Created by callmeDevil on 2019/8/4.
*/
public class Center extends Player {
// 代碼與前鋒相似
}
Guards
/**
* 後衛
* Created by callmeDevil on 2019/8/4.
*/
public class Guards extends Player {
// 代碼與前鋒相似
}
測試
public class Test {
public static void main(String[] args) {
Player b = new Forwards("巴蒂爾");
b.attack();
Player m = new Guards("麥克格雷迪");
m.attack();
Player ym = new Center("姚明");
// 姚明問:attack 和 defense 是什麼意思?
ym.attack();
ym.defense();
}
}
測試結果
前鋒 巴蒂爾 進攻
後衛 麥克格雷迪 進攻
中鋒 姚明 進攻
中鋒 姚明 防守
存在問題
姚明剛到NBA時可能英文還不太好,也就是說聽不懂教練的戰術安排,attach 和 defense 不知道什麼意思,因此這樣實現會有問題,需要一個中英翻譯。
適配器模式
定義
將一個類的介面轉換成客戶希望的另外一個介面。適配器模式使得原本由於介面不相容而不能一起工作的那些類可以一起工作。
分類
主要分為類適配器模式和對象適配器模式。由於類適配器模式通過多重繼承對一個介面與另一個介面進行匹配,而 Java 等語言不支持多重繼承,也就是一個類只有一個父類,所以這裡主要講的是對象適配器。
UML圖
代碼實現
ForeignCenter
/**
* 外籍中鋒
* Created by callmeDevil on 2019/8/4.
*/
public class ForeignCenter {
// 外籍中鋒球員的姓名故意用屬性而不是構造方法來區別與三個球員的不同
private String name;
// 表明外籍中鋒只懂中文“進攻”(註意:舉例效果,實際上千萬別用這種方式編程)
public void 進攻(){
System.out.println(String.format("外籍中鋒 %s 進攻", name));
}
// 表明外籍中鋒只懂中文“防守”(註意:舉例效果,實際上千萬別用這種方式編程)
public void 防守(){
System.out.println(String.format("外籍中鋒 %s 防守", name));
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Translator
/**
* 翻譯者
* Created by callmeDevil on 2019/8/4.
*/
public class Translator extends Player{
// 聲明並實例化一個內部“外籍中鋒”對象,表明翻譯者與外籍球員有關聯
private ForeignCenter wjzf = new ForeignCenter();
public Translator(String name){
super(name);
wjzf.setName(name);
}
@Override
public void attack() {
// 翻譯者將“attack”翻譯為“進攻”告訴外籍中鋒
wjzf.進攻();
}
@Override
public void defense() {
// 翻譯者將“defense”翻譯為“防守”告訴外籍中鋒
wjzf.防守();
}
}
測試
public class Test {
public static void main(String[] args) {
Player b = new Forwards("巴蒂爾");
b.attack();
Player m = new Guards("麥克格雷迪");
m.attack();
Player ym = new Translator("姚明");
// 翻譯者告訴姚明,教練要求你既要“進攻”又要“防守”
ym.attack();
ym.defense();
}
}
測試結果
前鋒 巴蒂爾 進攻
後衛 麥克格雷迪 進攻
外籍中鋒 姚明 進攻
外籍中鋒 姚明 防守
總結
- 系統的數據和行為都正確,但介面不符時,我們應該考慮用適配器,目的是使控制範圍之外的一個原有對象與某個介面匹配。
- 適配器模式主要應用於希望復用一些現存的類,但是介面又與復用環境要求不一致的情況。
- 使用已經存在的類,但如果它的介面,也就是它的方法和你的要求不相同時,就應該考慮用適配器模式。
- 兩個類所做的事情相同或相似,但是具有不同的介面時要使用它。
- 客戶代碼可以統一調用同一介面就行了,這樣可以更簡單、直接、緊湊。
- 在雙方都不太容易修改的時候再使用適配器模式適配。