前言:對(duì)于設(shè)計(jì)模式基礎(chǔ)概念可以去看[簡(jiǎn)說(shuō)設(shè)計(jì)模式之設(shè)計(jì)模式概述]
一、什么是適配器模式
適配器模式(Adapter)的定義如下:將一個(gè)類(lèi)的接口轉(zhuǎn)換成客戶(hù)希望的另外一個(gè)接口,使得原本由于接口不兼容而不能一起工作的那些類(lèi)能一起工作。適配器模式分為類(lèi)結(jié)構(gòu)型模式和對(duì)象結(jié)構(gòu)型模式兩種
1. 類(lèi)適配器
1.1 UML結(jié)構(gòu)圖

類(lèi)適配.gif
1.2 模式實(shí)現(xiàn)代碼
package adapter;
//目標(biāo)接口
interface Target
{
public void request();
}
//適配者接口
class Adaptee
{
public void specificRequest()
{
System.out.println("適配者中的業(yè)務(wù)代碼被調(diào)用!");
}
}
//類(lèi)適配器類(lèi)
class ClassAdapter extends Adaptee implements Target
{
public void request()
{
specificRequest();
}
}
//客戶(hù)端代碼
public class ClassAdapterTest
{
public static void main(String[] args)
{
System.out.println("類(lèi)適配器模式測(cè)試:");
Target target = new ClassAdapter();
target.request();
}
}
2.對(duì)象適配器
2.1 UML結(jié)構(gòu)圖

對(duì)象適配.gif
2.2 模式實(shí)現(xiàn)代碼
package adapter;
//對(duì)象適配器類(lèi)
class ObjectAdapter implements Target
{
private Adaptee adaptee;
public ObjectAdapter(Adaptee adaptee)
{
this.adaptee=adaptee;
}
public void request()
{
adaptee.specificRequest();
}
}
//客戶(hù)端代碼
public class ObjectAdapterTest
{
public static void main(String[] args)
{
System.out.println("對(duì)象適配器模式測(cè)試:");
Adaptee adaptee = new Adaptee();
Target target = new ObjectAdapter(adaptee);
target.request();
}
}
二、適配器模式的應(yīng)用
1. 何時(shí)使用
- 系統(tǒng)需要使用現(xiàn)有的類(lèi),而此類(lèi)的接口不符合系統(tǒng)的需要。
- 想建立一個(gè)可以重復(fù)使用的類(lèi),用于一些彼此之間沒(méi)有太大關(guān)聯(lián)的一些類(lèi)。
- 通過(guò)接口轉(zhuǎn)換,將一個(gè)類(lèi)插入另一個(gè)類(lèi)系中。
2. 方法
- 繼承或依賴(lài)。
3. 優(yōu)點(diǎn)
- 可以讓任何兩個(gè)沒(méi)有關(guān)聯(lián)的類(lèi)一起運(yùn)行。
- 增加了類(lèi)的透明性。我們?cè)L問(wèn)Target目標(biāo)角色,但具體實(shí)現(xiàn)都委托給了源角色,而這些對(duì)高層模塊是透明的,也是不需要關(guān)心的。
- 提高了類(lèi)的復(fù)用度。源角色在原有的系統(tǒng)中還是可以正常使用,而在目標(biāo)角色中也可以充當(dāng)新的演員。
- 靈活性非常好。什么時(shí)候不想要適配器了,直接刪掉就可以了,基本上就類(lèi)似一個(gè)靈活的構(gòu)件,想用就用,不想用就卸載。
4. 缺點(diǎn)
- 過(guò)多使用適配器,會(huì)使系統(tǒng)非常零亂。
- 由于Java至多繼承一個(gè)類(lèi),所以至多只能適配一個(gè)適配者類(lèi),而且目標(biāo)類(lèi)必須是抽象類(lèi)。
5. 使用場(chǎng)景
- 有動(dòng)機(jī)地修改一個(gè)正常運(yùn)行的系統(tǒng)的接口。
- 以前開(kāi)發(fā)的系統(tǒng)存在滿(mǎn)足新系統(tǒng)功能需求的類(lèi),但其接口同新系統(tǒng)的接口不一致。
- 使用第三方提供的組件,但組件接口定義和自己要求的接口定義不同。
6. 應(yīng)用實(shí)例
- 電源適配器。
- Java中的[JDBC]
7. 注意事項(xiàng)
- 只有碰到無(wú)法改變?cè)性O(shè)計(jì)和代碼的情況下,才考慮適配器模式。
三、適配器模式的擴(kuò)展
適配器模式(Adapter)可擴(kuò)展為雙向適配器模式,雙向適配器類(lèi)既可以把適配者接口轉(zhuǎn)換成目標(biāo)接口,也可以把目標(biāo)接口轉(zhuǎn)換成適配者接口,
1. UML結(jié)構(gòu)圖

雙適配模式.gif
2. 雙適配模式實(shí)現(xiàn)代碼
package adapter;
//目標(biāo)接口
interface TwoWayTarget
{
public void request();
}
//適配者接口
interface TwoWayAdaptee
{
public void specificRequest();
}
//目標(biāo)實(shí)現(xiàn)
class TargetRealize implements TwoWayTarget
{
public void request()
{
System.out.println("目標(biāo)代碼被調(diào)用!");
}
}
//適配者實(shí)現(xiàn)
class AdapteeRealize implements TwoWayAdaptee
{
public void specificRequest()
{
System.out.println("適配者代碼被調(diào)用!");
}
}
//雙向適配器
class TwoWayAdapter implements TwoWayTarget,TwoWayAdaptee
{
private TwoWayTarget target;
private TwoWayAdaptee adaptee;
public TwoWayAdapter(TwoWayTarget target)
{
this.target=target;
}
public TwoWayAdapter(TwoWayAdaptee adaptee)
{
this.adaptee=adaptee;
}
public void request()
{
adaptee.specificRequest();
}
public void specificRequest()
{
target.request();
}
}
//客戶(hù)端代碼
public class TwoWayAdapterTest
{
public static void main(String[] args)
{
System.out.println("目標(biāo)通過(guò)雙向適配器訪問(wèn)適配者:");
TwoWayAdaptee adaptee=new AdapteeRealize();
TwoWayTarget target=new TwoWayAdapter(adaptee);
target.request();
System.out.println("-------------------");
System.out.println("適配者通過(guò)雙向適配器訪問(wèn)目標(biāo):");
target=new TargetRealize();
adaptee=new TwoWayAdapter(target);
adaptee.specificRequest();
}
}
四、類(lèi)適配器和對(duì)象適配器的區(qū)別
從上面的內(nèi)容可以看出來(lái),類(lèi)適配器是類(lèi)間繼承,對(duì)象適配器是對(duì)象的合成關(guān)系,也可以說(shuō)是類(lèi)的關(guān)聯(lián)關(guān)系,這是兩者的根本區(qū)別。
? 由于對(duì)象適配器是通過(guò)類(lèi)間的關(guān)聯(lián)關(guān)系進(jìn)行耦合的,因此在設(shè)計(jì)時(shí)就可以做到比較靈活,而類(lèi)適配器就只能通過(guò)覆寫(xiě)源角色的方法進(jìn)行擴(kuò)展。
? 在實(shí)際項(xiàng)目中,對(duì)象適配器使用到的場(chǎng)景較多。