現(xiàn)實生活中的適配器例子:
一 基本介紹
適配器模式(Adapter Pattern)將某個類的接口轉(zhuǎn)換成客戶端期望的另一個接口表示,主的目的是兼容性,讓原本因接口不匹配不能一起工作的兩個類可以協(xié)同工作。其別名為包裝器(Wrapper)
適配器模式屬于結(jié)構(gòu)型模式
主要分為三類:類適配器模式、對象適配器模式、接口適配器模式
二 工作原理
適配器模式:將一個類的接口轉(zhuǎn)換成另一種接口.讓原本接口不兼容的類可以兼容
從用戶的角度看不到被適配者,是解耦的
用戶調(diào)用適配器轉(zhuǎn)化出來的目標接口方法,適配器再調(diào)用被適配者的相關(guān)接口方法
用戶收到反饋結(jié)果,感覺只是和目標接口交互,如圖
三 類適配器模式
3.1 類適配器模式介紹
基本介紹:Adapter 類,通過繼承 src 類,實現(xiàn) dst 類接口,完成 src->dst 的適配。
3.2 類適配器模式應(yīng)用實例
- 應(yīng)用實例說明
以生活中充電器的例子來講解適配器,充電器本身相當于 Adapter,220V 交流電相當于 src (即被適配者),我們的目 dst(即 目標)是 5V 直流電
- 思路分析(類圖)
- 代碼實現(xiàn)
public class Client {
public static void main(String[] args){
System.out.println(" === 類適配器模式 ====");
Phone phone = new Phone();
phone.charging(new VoltageAdapter ());
}
}
適配器接口:
public interface IVoltage5V {
public int output5V();
}
充電:
public class Phone {
public void charging(IVoltage5V iVoltage5V) {
if (iVoltage5V.output5V() == 5) {
System.out.println("電壓為 5V, 可以充電~~");
} else if (iVoltage5V.output5V() > 5) {
System.out.println("電壓大于 5V, 不能充電~~");
}
}
}
被適配的類:
public class Voltage220V {
//輸出 220V 的電壓
public int output220V() { int src = 220;
System.out.println("電壓=" + src + "伏");
return src;
}
}
適配器類:
public class VoltageAdapter extends Voltage220V implements IVoltage5V {
@Override
public int output5V() {
//獲取到 220V 電壓
int srcV = output220V();
int dstV = srcV / 44 ; //轉(zhuǎn)成 5v
return dstV;
}
}
- 類適配器模式注意事項和細節(jié)
- Java 是單繼承機制,所以類適配器需要繼承 src 類這一點算是一個缺點, 因為這要求 dst 必須是接口,有一定局限性;
- src 類的方法在 Adapter 中都會暴露出來,也增加了使用的成本。
- 由于其繼承了 src 類,所以它可以根據(jù)需求重寫 src 類的方法,使得 Adapter 的靈活性增強了。
四 對象適配器模式
4.1 對象適配器模式介紹
基本思路和類的適配器模式相同,只是將 Adapter 類作修改,不是繼承 src 類,而是持有 src 類的實例,以解決兼容性的問題。 即:持有 src 類,實現(xiàn) dst 類接口,完成 src->dst 的適配
根據(jù)“合成復(fù)用原則”,在系統(tǒng)中盡量使用關(guān)聯(lián)關(guān)系(聚合)來替代繼承關(guān)系。
對象適配器模式是適配器模式常用的一種
4.2 對象適配器模式應(yīng)用實例
- 應(yīng)用實例說明
以生活中充電器的例子來講解適配器,充電器本身相當于 Adapter,220V 交流電相當于 src (即被適配者),我們的目 dst(即目標)是 5V 直流電,使用對象適配器模式完成。 - 思路分析(類圖):只需修改適配器即可, 如下:
代碼實現(xiàn):
public class VoltageAdapter implements IVoltage5V {
private Voltage220V voltage220V; // 關(guān)聯(lián)關(guān)系-聚合
//通過構(gòu)造器,傳入一個 Voltage220V 實例
public VoltageAdapter(Voltage220V voltage220v) {
this.voltage220V = voltage220v;
}
@Override
public int output5V() {
int dst = 0;
if(null != voltage220V) {
int src = voltage220V.output220V();//獲取 220V 電壓
System.out.println("使用對象適配器,進行適配~~");
dst = src / 44;
System.out.println("適配完成,輸出的電壓為=" + dst);
}
return dst;
}
}
4.3 對象適配器模式注意事項和細節(jié)
對象適配器和類適配器其實算是同一種思想,只不過實現(xiàn)方式不同。
根據(jù)合成復(fù)用原則,使用組合替代繼承, 所以它解決了類適配器必須繼承 src 的局限性問題,也不再要求 dst
必須是接口。使用成本更低,更靈活。
五. 接口適配器模式
5.1 接口適配器模式介紹
核心思路:當不需要全部實現(xiàn)接口提供的方法時,可先設(shè)計一個抽象類實現(xiàn)接口,并為該接口中每個方法提供一個默認實現(xiàn)(空方法),那么該抽象類的子類可有選擇地覆蓋父類的某些方法來實現(xiàn)需求
適用于一個接口不想使用其所有的方法的情況。
-
案例說明
image.png
代碼展示:
public interface Interface4 {
public void m1();
public void m2();
public void m3();
public void m4();
}
public abstract class AbsAdapter implements Interface4 {
//默認實現(xiàn)
public void m1() {
}
public void m2() {
}
public void m3() {
}
public void m4() {
}
}
public class Client {
public static void main(String[] args) {
AbsAdapter absAdapter = new AbsAdapter() {
//只需要去覆蓋我們 需要使用 接口方法
@Override
public void m1() {
System.out.println("使用了 m1 的方法");
}
};
absAdapter.m1();
}
}
六.適配器模式的注意事項和細節(jié)
- 三種命名方式,是根據(jù) src 是以怎樣的形式給到 Adapter(在 Adapter 里的形式)來命名的。
- 類適配器:以類給到,在 Adapter 里,就是將 src 當做類,繼承
對象適配器:以對象給到,在 Adapter 里,將 src 作為一個對象,持有接口適配器:以接口給到,在 Adapter 里,將 src 作為一個接口,實現(xiàn) - Adapter 模式最大的作用還是將原本不兼容的接口融合在一起工作。
- 實際開發(fā)中,實現(xiàn)起來不拘泥于我們講解的三種經(jīng)典形式
七. 適配器模式應(yīng)用場景
SpringMvc 中的 HandlerAdapter, 就使用了適配器模式
類適配器與對象適配器的使用場景一致,僅僅是實現(xiàn)手段稍有區(qū)別,二者主要用于如下場景:
(1)想要使用一個已經(jīng)存在的類,但是它卻不符合現(xiàn)有的接口規(guī)范,導(dǎo)致無法直接去訪問,這時創(chuàng)建一個適配器就能間接去訪問這個類中的方法。
(2)我們有一個類,想將其設(shè)計為可重用的類(可被多處訪問),我們可以創(chuàng)建適配器來將這個類來適配其他沒有提供合適接口的類。
以上兩個場景其實就是從兩個角度來描述一類問題,那就是要訪問的方法不在合適的接口里,一個從接口出發(fā)(被訪問),一個從訪問出發(fā)(主動訪問)。
接口適配器使用場景:
(1)想要使用接口中的某個或某些方法,但是接口中有太多方法,我們要使用時必須實現(xiàn)接口并實現(xiàn)其中的所有方法,可以使用抽象類來實現(xiàn)接口,并不對方法進行實現(xiàn)(僅置空),然后我們再繼承這個抽象類來通過重寫想用的方法的方式來實現(xiàn)。這個抽象類就是適配器。