1. 程式人生 > 實用技巧 >大話設計模式讀書筆記(介面卡模式)

大話設計模式讀書筆記(介面卡模式)

人物:大鳥,小菜

事件:大鳥和小菜看NBA,討論姚明,說姚明這幾年不但球技大漲,而且也能用英語順利交流了,最開始去NBA時還需要翻譯,才能和隊友教練溝通。大鳥這時想到了介面卡模式,並傳授給了小菜


介面卡模式:

1.簡介介面卡模式

2.用程式碼實現教練指揮打籃球

3.用介面卡模式幫助姚明翻譯英語,聽懂戰術

4.舉例加深印象 --魏文王問扁鵲

介面卡模式

1.概念:將一個類的介面轉換成客戶希望的另外一個介面。Adapter模式使得原本由於介面不相容而不能一起工作的那些類可以一起工作。

2.舉例:姚明的翻譯就是介面卡

3.介面卡模式講了兩種型別:類介面卡模式和物件介面卡模式

4.介面卡結構圖:

5.介面卡模式程式碼:

Target類,這是客戶所期待的介面,目標可以是具體的或抽象的類,也可以是介面:

@Slf4j
public class Target {
    public void request() {
        log.info("普通請求!");
    }
}

Adaptee類,需要適配的類:

@Slf4j
public class Adaptee {
    public void specificRequest() {
        log.info("特殊請求!");
    }
}

Adapter類,通常在內部包裝一個Adaptee物件,把源介面轉換為目標介面:

public class Adapter extends Target {
    private Adaptee adaptee = new Adaptee();

    @Override
    public void request() {
        adaptee.specificRequest();
    }
}

客戶端程式碼:

public class AdapterClient {
    public static void main(String[] args) {
        Target target = new Adapter();
        target.request();
        Target aim 
= new Target(); aim.request(); } }

輸出結果:

特殊請求!
普通請求!

6.什麼時候使用介面卡模式?

答:兩個類做的事情相同或相似,但具有不同的介面時可以使用,而且前提是在雙方都不太容易修改的情況下才使用(有點亡羊補牢的感覺)

籃球翻譯介面卡

球員:

public abstract class Player {
    protected String name;

    public Player(String name) {
        this.name = name;
    }

    public abstract void attack();

    public abstract void defense();
}

後衛,中鋒,前鋒類

@Slf4j
public class Guards extends Player {
    public Guards(String name) {
        super(name);
    }

    @Override
    public void attack() {
        log.info("後衛{}, 進攻", name);
    }

    @Override
    public void defense() {
        log.info("後衛{}, 防守", name);
    }
}
@Slf4j
public class Center extends Player {


    public Center(String name) {
        super(name);
    }

    @Override
    public void attack() {
        log.info("中鋒{}, 進攻", name);
    }

    @Override
    public void defense() {
        log.info("中鋒{}, 防守", name);
    }
}
@Slf4j
public class Forwards extends Player {
    
    public Forwards(String name) {
        super(name);
    }

    @Override
    public void attack() {
        log.info("前鋒{}, 進攻", name);
    }

    @Override
    public void defense() {
        log.info("前鋒{}, 防守", name);
    }
}

客戶端程式碼:

public class AdapterClient {
    public static void main(String[] args) {
        Player b = new Forwards("巴蒂爾");
        b.attack();
        Player m = new Guards("麥克格雷迪");
        m.attack();

        Player ym = new Center("姚明");
        ym.attack();
        ym.defense();
    }
}

大鳥:注意,姚明剛來NBA,還聽不懂英語,無法和教練進行戰術溝通,不知道attack和defense的意思,現在就需要改動程式碼進行適配

適配後的籃球隊

新加外籍中鋒類:

@Data
@Slf4j
public class ForeignCenter {
    private String name;

    //這裡表明'外籍中鋒'只懂得中文'進攻'
    public void 進攻() {
        log.info("外籍中鋒{} 進攻", name);
    }

    //這裡表明'外籍中鋒'只懂得中文'防守'
    public void 防守() {
        log.info("外籍中鋒{}, 防守", name);
    }
}

翻譯者類(即進行適配):

public class Translator extends Player {
    private ForeignCenter wjzf = new ForeignCenter();

    public Translator(String name) {
        super(name);
        wjzf.setName(name);
    }

    @Override
    public void attack() {
        wjzf.進攻();
    }

    @Override
    public void defense() {
        wjzf.防守();
    }
}

客戶端程式碼:

public class AdapterClient {
    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(); } }

加深印象

最後借大話設計模式的舉例來加深印象(例子很生動):

魏文王問名醫扁鵲說:“你們家兄弟三人,都精於醫術,到底哪一位最好呢?”
扁鵲答:“長兄最好,中兄次之,我最差。”文王再問:“那麼為什麼你最出名呢?”扁鵲答:“長兄治病,是治病於病情發作之前。由於一般人不知道他事先能剷除病因,所以他的名氣無法傳出去;中兄治病,是治病於病情初起時。一般人以為他只能治輕微的小病,所以他的名氣只及本鄉里。而我是治病於病情嚴重之時。一般人都看到我在經脈上穿針管放血、在面板上敷藥等大手術,所以以為我的醫術高明,名氣因此響遍全國。”

程式設計同理,如果能事先預防介面不同或不匹配的問題,那麼問題就不會發生;有小的問題不匹配時及時重構,問題也不至於擴大;只有碰到無法改變原有設計和程式碼的情況下時,才考慮適配。事後控制不如事中控制,事中控制不如事前控制,如果能事前控制,又何必去彌補呢。注意,介面卡模式固然是好模式,如果無視它的應用場合而盲目使用,就是本末倒置了。