1.概述
(1)如果去歐洲國家去旅游的話,他們的插座如下圖最左邊,是歐洲標(biāo)準(zhǔn)。而我們使用的插頭如下圖最右邊的。因此我們的筆記本電腦,手機(jī)在當(dāng)?shù)夭荒苤苯映潆姟K跃托枰粋€(gè)插座轉(zhuǎn)換器,轉(zhuǎn)換器第1面插入當(dāng)?shù)氐牟遄?面供我們充電,這樣使得我們的插頭在當(dāng)?shù)啬苁褂?。生活中這樣的例子很多,手機(jī)充電器(將 220V 轉(zhuǎn)換為 5V 的電壓),讀卡器等,其實(shí)就是使用到了適配器模式。
(2)適配器模式 (Adapter Pattern) 是一種結(jié)構(gòu)型設(shè)計(jì)模式,它通過將一個(gè)類的接口轉(zhuǎn)換成客戶端所期望的另一個(gè)接口,使得原本由于接口不兼容而無法一起工作的類能夠協(xié)同工作。適配器模式分為類適配器模式和對象適配器模式,前者類之間的耦合度比后者高,且要求程序員了解現(xiàn)有組件庫中的相關(guān)組件的內(nèi)部結(jié)構(gòu),故應(yīng)用相對較少。
2.結(jié)構(gòu)
適配器模式 (Adapter) 包含以下主要角色:
- 目標(biāo) (Target) 接口:當(dāng)前系統(tǒng)業(yè)務(wù)所期待的接口,它可以是抽象類或接口。
- 被適配 (Adaptee) 類:它是被訪問和適配的現(xiàn)存組件庫中的組件接口。
- 適配器 (Adapter) 類:它是一個(gè)轉(zhuǎn)換器,通過繼承或引用適配者的對象,把適配者接口轉(zhuǎn)換成目標(biāo)接口,讓客戶按目標(biāo)接口的格式訪問適配者。
3.類適配器模式
實(shí)現(xiàn)方式:定義一個(gè)適配器類來實(shí)現(xiàn)當(dāng)前系統(tǒng)的業(yè)務(wù)接口,同時(shí)又繼承現(xiàn)有組件庫中已經(jīng)存在的組件。
【讀卡器】:現(xiàn)有一臺(tái)電腦只能讀取 SD 卡,而要讀取 TF 卡中的內(nèi)容的話就需要使用到適配器模式。創(chuàng)建一個(gè)讀卡器,將 TF 卡中的內(nèi)容讀取出來。類圖如下:
具體代碼如下:
3.1.目標(biāo)接口
SDCard.java
//目標(biāo)接口
public interface SDCard {
//從 SD 卡中讀取數(shù)據(jù)
String readSD();
//往 SD 卡中寫數(shù)據(jù)
void writeSD(String msg);
}
SDCardImpl.java
public class SDCardImpl implements SDCard{
@Override
public String readSD() {
String msg = "SDCard read msg : hello word SD";
return msg;
}
@Override
public void writeSD(String msg) {
System.out.println("SDCard write msg :" + msg);
}
}
3.2.被適配類
TFCard.java
//被適配類的接口
public interface TFCard {
//從TF卡中讀數(shù)據(jù)
String readTF();
//從THF卡中寫數(shù)據(jù)
void writeTF(String msg);
}
TFCardImpl.java
//適配者類
public class TFCardImpl implements TFCard{
@Override
public String readTF() {
String msg = "TFCard read msg :hello word TFCard";
return msg;
}
@Override
public void writeTF(String msg) {
System.out.println("TFCard write msg :"+msg);
}
}
3.3.適配器類
ADAdapterTF.java
//適配器類
public class ADAdapterTF extends TFCardImpl implements SDCard{
@Override
public String readSD() {
System.out.println("adapter read tf card");
return readTF();
}
@Override
public void writeSD(String msg) {
System.out.println("adapter write tf card");
writeTF(msg);
}
}
Computer.java
//計(jì)算機(jī)類
public class Computer {
//從 SD 卡中讀取數(shù)據(jù)
public String readSD(SDCard sdCard) {
if (sdCard == null) {
throw new NullPointerException("sd card cannot be null");
}
return sdCard.readSD();
}
}
3.4.測試
Client.java
public class Client {
public static void main(String[] args) {
//創(chuàng)建計(jì)算機(jī)對象
Computer computer = new Computer();
String msg = computer.readSD(new SDCardImpl());
System.out.println(msg);
System.out.println("=============");
//使用該電腦讀取 TF 卡中的數(shù)據(jù)
String msg1 = computer.readSD(new ADAdapterTF());
System.out.println(msg1);
}
}
注:類適配器模式違背了合成復(fù)用原則。類適配器是客戶類有一個(gè)接口規(guī)范的情況下可用,反之不可用。
4.對象適配器模式
實(shí)現(xiàn)方式:對象適配器模式可釆用將現(xiàn)有組件庫中已經(jīng)實(shí)現(xiàn)的組件引入適配器類中,該類同時(shí)實(shí)現(xiàn)當(dāng)前系統(tǒng)的業(yè)務(wù)接口。還是以上面的讀卡器為例進(jìn)行改寫,類圖如下:
對于類適配器模式的代碼,只需要修改適配器類 (SDAdapterTF) 和 測試類 (Client) 即可,修改后的代碼如下:
- SDAdapterTF.java
//適配器類
public class SDAdapterTF implements SDCard {
//聲明適配者類
private TFCard tfCard;
public SDAdapterTF(TFCard tfCard){
this.tfCard = tfCard;
}
@Override
public String readSD() {
System.out.println("adapter read tf card");
return tfCard.readTF();
}
@Override
public void writeSD(String msg) {
System.out.println("adapter write tf card");
tfCard.writeTF(msg);
}
}
- Client.java
public class Client {
public static void main(String[] args) {
//創(chuàng)建計(jì)算機(jī)對象
Computer computer = new Computer();
String msg = computer.readSD(new SDCardImpl());
System.out.println(msg);
System.out.println("===============");
//使用該電腦讀取 TF 卡中的數(shù)據(jù)
//創(chuàng)建適配器類對象
SDAdapterTF sdAdapterTF = new SDAdapterTF(new TFCardImpl());
String msg1 = computer.readSD(sdAdapterTF);
System.out.println(msg1);
}
}
注意:還有一個(gè)適配器模式是接口適配器模式,當(dāng)不希望實(shí)現(xiàn)一個(gè)接口中所有的方法時(shí),可以創(chuàng)建一個(gè)抽象類Adapter,實(shí)現(xiàn)所有方法。而此時(shí)我們只需要繼承該抽象類即可。
5.優(yōu)缺點(diǎn)
(1)適配器模式有以下優(yōu)點(diǎn)和缺點(diǎn):
-
優(yōu)點(diǎn)
- 轉(zhuǎn)換不兼容的接口:適配器模式能夠?qū)⒁粋€(gè)類的接口轉(zhuǎn)換成另一個(gè)類的接口,使得原本由于接口不兼容而無法一起工作的類能夠協(xié)同工作。
- 透明性:適配器模式可以讓客戶端代碼與原有接口解耦,無需修改原有代碼,只需通過適配器進(jìn)行適配即可。
- 復(fù)用已有類:適配器模式可以重用現(xiàn)有的類,通過適配器轉(zhuǎn)換后,這些類可以與其他不兼容的接口進(jìn)行工作。
- 靈活性:適配器模式可以在系統(tǒng)中引入新的類,并將其與現(xiàn)有的類一起工作,而無需修改現(xiàn)有的代碼。這使得系統(tǒng)更加靈活,能夠方便地進(jìn)行擴(kuò)展和維護(hù)。
-
缺點(diǎn)
- 類型數(shù)量增加:引入適配器類可能會(huì)增加代碼中的類的數(shù)量,使得代碼的結(jié)構(gòu)復(fù)雜化。
- 過多的適配器:如果系統(tǒng)中存在大量的不兼容接口,就會(huì)導(dǎo)致需要大量的適配器類,增加了系統(tǒng)的復(fù)雜性。
- 性能損失:適配器模式可能會(huì)導(dǎo)致性能損失,因?yàn)樵谶M(jìn)行接口轉(zhuǎn)換時(shí)需要額外的邏輯處理。
(2)需要根據(jù)具體的使用場景和需求綜合考慮適配器模式的使用。適配器模式在解決接口不兼容的問題上具有一定的優(yōu)勢,但也需要注意適配器模式的適用范圍,避免濫用和過度設(shè)計(jì)。
6.應(yīng)用場景
(1)適配器模式適用于以下場景:
- 系統(tǒng)需要使用已有的類,但其接口與系統(tǒng)要求的接口不匹配。適配器模式可以將已有類的接口適配成系統(tǒng)所需的接口。
- 需要復(fù)用現(xiàn)有類,在現(xiàn)有類的基礎(chǔ)上進(jìn)行功能擴(kuò)展,但原有類的接口無法直接滿足需求。適配器模式可以通過適配器來擴(kuò)展已有類的功能,使其適配新的接口。
- 在系統(tǒng)中引入新的類,但該類的接口與系統(tǒng)的其他組件不兼容。適配器模式可以將新類的接口轉(zhuǎn)換成系統(tǒng)要求的接口,使其與其他組件協(xié)同工作。
- 不同團(tuán)隊(duì)開發(fā)的兩個(gè)系統(tǒng)需要進(jìn)行集成,但其接口不兼容。適配器模式可以將兩個(gè)系統(tǒng)的接口進(jìn)行適配,使其能夠協(xié)同工作。
- 需要設(shè)計(jì)一個(gè)可復(fù)用的類,它需要與其他不兼容的接口一起工作。適配器模式可以將該類的接口適配成其他不兼容接口,使其能夠與其他組件協(xié)同工作。
(2)總之,適配器模式適用于在不兼容接口之間進(jìn)行轉(zhuǎn)換的場景。它可以使原本不兼容的類能夠協(xié)同工作,提高代碼的復(fù)用性和靈活性。在軟件開發(fā)過程中,適配器模式經(jīng)常被用于系統(tǒng)集成、API 設(shè)計(jì)、舊系統(tǒng)的功能擴(kuò)展等方面。
7.JDK 源碼解析——InputStreamReader
(1)Reader(字符流)、InputStream(字節(jié)流)的適配使用的是 InputStreamReader。 InputStreamReader 繼承自 java.io
包中的 Reader
,對它中的抽象的未實(shí)現(xiàn)的方法給出實(shí)現(xiàn)。InputStreamReader
類中的部分源代碼如下:
package java.io;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import sun.nio.cs.StreamDecoder;
public class InputStreamReader extends Reader {
// StreamDecoder 繼承了 Read
private final StreamDecoder sd;
......
public int read() throws IOException {
return sd.read();
}
public int read(char cbuf[], int offset, int length) throws IOException {
return sd.read(cbuf, offset, length);
}
......
}
(2)如上代碼中的 sd(StreamDecoder 類對象),在 Sun 的 JDK 實(shí)現(xiàn)中,實(shí)際的方法實(shí)現(xiàn)是對 sun.nio.cs.StreamDecoder
類的同名方法的調(diào)用封裝。類結(jié)構(gòu)圖如下:
(3)從上圖可以看出:文章來源:http://www.zghlxwxcb.cn/news/detail-570161.html
- InputStreamReader 是對同樣實(shí)現(xiàn)了 Reader 的 StreamDecoder 的封裝。
- StreamDecoder 不是 Java SE API 中的內(nèi)容,是 Sun JDK 給出的自身實(shí)現(xiàn)。但我們知道他們對構(gòu)造方法中的字節(jié)流類 (InputStream) 進(jìn)行封裝,并通過該類進(jìn)行了字節(jié)流和字符流之間的解碼轉(zhuǎn)換。
(4)結(jié)論:從表層來看,InputStreamReader 做了 InputStream 字節(jié)流類到 Reader 字符流之間的轉(zhuǎn)換。而從如上 Sun JDK 中的實(shí)現(xiàn)類關(guān)系結(jié)構(gòu)中可以看出,是 StreamDecoder 的設(shè)計(jì)實(shí)現(xiàn)在實(shí)際上采用了適配器模式。文章來源地址http://www.zghlxwxcb.cn/news/detail-570161.html
到了這里,關(guān)于Java 設(shè)計(jì)模式——適配器模式的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!