設計模式 | 適配器模式(adapter)

定義:

將一個類的接口轉換成客戶但願的另一個接口。Adapter模式使得本來因爲接口不兼容而不能一塊兒工做的那些類能夠一塊兒工做。
 
書中說到Gof的設計模式中,講了兩種類型的適配器模式:
1.類適配器模式
2.對象適配器模式
其中,類適配器模式,是經過多重繼承來實現了。
可是Java是不支持多重繼承的,因此下面主要講的是對象適配器模式。
 

結構:(書中圖,侵刪)

 

一個客戶真正要使用的目標接口(具體一點說能夠叫方法),包含它的能夠是接口、抽象類、類
一個須要被適配的接口(方法),同上
一個適配器,繼承自目標接口,包含一個須要被適配的接口
 

實例:

書中提到一個電源適配器的例子,很形象,因此這裏提一嘴。
就是中國的電源是220V,但有的國家是110V,出國以後依舊想使用中國的電器怎麼辦?就須要用到適配器來轉換一下電壓。
說到這裏,我就想到了一個例子,護照。
中國公民有中國的身份證,外國人也有外國的id card,咱們不能期望外國人都用中國的身份證,一樣咱們也不可能都使用外國的id card。
可是出入境怎麼驗證你的身份呢,這就須要用到護照,護照就至關於全球通用的身份證。咱們這裏忽略簽證的存在,簽證也要蓋在護照上不是。
 
目標類(外國身份認證):
package designpattern.adapter;

import java.util.HashSet;
import java.util.Set;

public class ForeignIdentify {
    String socailSecurityNumber;

    // 模擬一個社保號的數據庫
    static Set<String> dbSet = new HashSet<>();
    static {
        dbSet.add("F001");
        dbSet.add("F002");
        dbSet.add("F003");
    }

    public boolean check(String socailSecurityNumber) {
        if (dbSet.contains(socailSecurityNumber)) {
            System.out.println(socailSecurityNumber + "是外國的合法公民");
            return true;
        } else {
            System.out.println(socailSecurityNumber + "不是外國的合法公民");
            return false;
        }

    }
}
被適配類(中國身份認證):
package designpattern.adapter;

import java.util.HashSet;
import java.util.Set;

public class ChineseIdentify {
    String idCardNumber;

    // 模擬一個身份證號的數據庫
    static Set<String> dbSet = new HashSet<>();
    static {
        dbSet.add("張三C001");
        dbSet.add("李四C002");
        dbSet.add("王五C003");
    }

    public boolean check(String idCardNumber, String name) {
        if (dbSet.contains(name + idCardNumber)) {
            System.out.println(name + idCardNumber + "是中國的合法公民");
            return true;
        } else {
            System.out.println(name + idCardNumber + "不是中國的合法公民");
            return false;
        }

    }
}
適配器(護照):
package designpattern.adapter;

import java.util.HashMap;
import java.util.Map;

public class ChinesePassport extends ForeignIdentify {
    ChineseIdentify chineseIdentify = new ChineseIdentify();
    
    // 模擬身份證、名字對應數據庫
    static Map<String, String> db = new HashMap<>();
    static {
        db.put("C001", "張三");
        db.put("C002", "李四");
        db.put("C003", "王五");

    }

    @Override
    public boolean check(String idCardNumber) {
        // 爲了模擬兩個接口不徹底同樣,假設中國的身份驗證須要身份證號和名字兩個條件
        return chineseIdentify.check(idCardNumber, getName(idCardNumber));
    }

    private String getName(String idCardNumber) {
        return db.get(idCardNumber);
    }
}
客戶端:
package designpattern.adapter;

public class Client {
    public static void main(String[] args) {

        ForeignIdentify foreignIdentify = new ForeignIdentify();
        enter("F001", foreignIdentify);
        enter("F004", foreignIdentify);

        // 直接用身份證號來驗證
        enter("C003", foreignIdentify);
        // 換成護照
        foreignIdentify = new ChinesePassport();
        enter("C003", foreignIdentify);
    }

    public static void enter(String number, ForeignIdentify foreignIdentify) {
        System.out.println("=============外國入關==============");
        if (foreignIdentify.check(number)) {
            System.out.println("容許入關!");
        } else {
            System.out.println("禁止入關!");
        }

    }
}

結果輸出:java

=============外國入關==============
F001是外國的合法公民
容許入關!
=============外國入關==============
F004不是外國的合法公民
禁止入關!
=============外國入關==============
C003不是外國的合法公民
禁止入關!
=============外國入關==============
王五C003是中國的合法公民
容許入關!

總結:

這個模式準確的說是一個無奈的選擇,不該該當作第一選擇,當須要適配的兩樣東西很差改動的時候,爲了讓他們能匹配上,纔不得不使用適配器。
若是可以提早避免接口不匹配的狀況,及時進行代碼的重構是更好的選擇。就像若是說有電子設備都是一樣的充電口,那咱們就不須要準備他們多條充電線了。
相關文章
相關標籤/搜索