大話設計模式筆記(十四)の適配器模式

舉個栗子

問題描述

不同國家的人在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();
    }
}

測試結果

前鋒 巴蒂爾 進攻
後衛 麥克格雷迪 進攻
外籍中鋒 姚明 進攻
外籍中鋒 姚明 防守

總結

  • 系統的數據和行爲都正確,但接口不符時,我們應該考慮用適配器,目的是使控制範圍之外的一個原有對象與某個接口匹配。
  • 適配器模式主要應用於希望複用一些現存的類,但是接口又與複用環境要求不一致的情況。
  • 使用已經存在的類,但如果它的接口,也就是它的方法和你的要求不相同時,就應該考慮用適配器模式。
  • 兩個類所做的事情相同或相似,但是具有不同的接口時要使用它。
  • 客戶代碼可以統一調用同一接口就行了,這樣可以更簡單、直接、緊湊。
  • 在雙方都不太容易修改的時候再使用適配器模式適配。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章