The Adapter Pattern converts the interface of a class into another interface the clients expect. Adapter lets classes work together that couldn't otherwise because of incompatible interfaces.
翻譯年糕:適配器模式將一個類別的介面轉換成客戶希望的另外一個介面,Adapter使得原本由於介面相容而不能一起工作的那些類別可以一起工作
最常見的例子就是電器插頭與插座。當出國玩時,一定會有使用電器的需求。但每個國家的插座及電壓都不一樣,那該怎麼辦?這時你就會拿出你事先準備好的轉接頭,藉由轉接頭將插座與電器插頭做連接。生活上還有許多的例子,如type-c轉hdmi線...等等。
又到了介紹家族成員的時候了。Adapter Pattern內有三個成員
成員 | 功用 |
---|---|
Target | 定義著所需要的方法,可以是抽象類別或是介面。如:國外的插座。(白話文:想要變成的對象) |
Adaptee | 為呼叫和配接的元件中的组件接口。如:身上的電器插頭。(白話文:想變身的對象) |
Adapter | 為一個轉換器,通過繼承或是合成的方式,將Adaptee的接口轉換成Adapter接口,Client直接呼叫Adapter接口就可以執行Adaptee的方法。如:轉接頭。(白話文:把想變身的對象變成他想變成的對象,這邊稱他上帝XD) |
Adapter Pattern內有分兩種模式,一種是物件結構型模式,另一種是類別結構型模式。類別結構型模式的耦合度會比物件模式要高,且類別結構型模式使用多繼承,所以不能使用在JAVA中。
在這種模式中,用合成的方式,將Adaptee放入Adapter中。
註:什麼是合成,可參考這篇:汽油車 & 電動車 - 合成/聚合複用原則 | Composite/Aggregate Reuse Principle內的合成 v.s 聚合
interface Target {
public void request();
}
class Adaptee {
public void specificRequest() {
System.out.println("run specificRequest in Adaptee class");
}
}
class ObjectAdapter implements Target {
private Adaptee adaptee;
public ObjectAdapter(Adaptee adaptee)
{
this.adaptee=adaptee;
}
public void request()
{
adaptee.specificRequest();
}
}
public class ObjectAdapterTest {
public static void main(String[] args)
{
System.out.println("ObjectAdapterTest:");
Adaptee adaptee = new Adaptee();
Target target = new ObjectAdapter(adaptee);
target.request();
}
}
output
ObjectAdapterTest:
run specificRequest in Adaptee class
透過多重繼承來實現,adapter同時繼承兩個以上的類別。這種方式在支援多繼承的語言中出現,如:C++、python。而Java中無法實作多重繼承,但可以定義一個Adapter來實作Target,同時繼承Adaptee的方式來實現Class Adapter。
python範例:
class Adaptee1:
def doAction1(self):
print("action 1")
class Adaptee2:
def doAction2(self):
print("action 2")
class Adaptor(Adaptee1, Adaptee2):
def doRequest(self):
self.doAction1()
self.doAction2()
print("request")
adaptor = Adaptor()
adaptor.doRequest()
output
action 1
action 2
request
註:可將程式碼在 online_python_compiler 執行
Java範例:
interface Target {
public void request();
}
class Adaptee {
public void specificRequest()
{
System.out.println("run specificRequest in Adaptee class");
}
}
class ClassAdapter extends Adaptee implements Target {
public void request()
{
specificRequest();
}
}
public class ClassAdapterTest {
public static void main(String[] args)
{
System.out.println("ClassAdapterTest:");
Target target = new ClassAdapter();
target.request();
}
}
output
ClassAdapterTest:
run specificRequest in Adaptee class
雖然Java這樣依舊可以執行,但如果要有多個Adaptee,Class Adapter就不在適用了。
看完Adapter Pattern的成員以及兩種Adapter之後,就來實作看看Adapter Pattern吧!
來用小紅帽與大野狼的故事來寫看看Adapter Pattern。大野狼為了把小紅帽吃了,所以到老奶奶家,先把奶奶吃了,再假扮成奶奶。我們就不實作吃奶奶的步驟了,直接從假扮奶奶開始。
分別將奶奶與大野狼的Target做出來,然後再分別實作他們。
interface Grandma {
public void snore();
public void sleep();
}
interface Wolf {
public void bark();
public void sleep();
}
class RedHatGrandma implements Grandma {
@Override
public void snore() {
System.out.println("Grandma snore");
}
@Override
public void sleep() {
System.out.println("Grandma sleeping");
}
}
class BigWildWolf implements Wolf {
@Override
public void bark() {
System.out.println("BigWildWolf bark");
System.out.println("BigWildWolf imitate Grandma snore");
}
@Override
public void sleep() {
System.out.println("BigWildWolf sleeping");
}
}
接著建立大野狼Adapter,由於大野狼要假扮奶奶,所以他要實作奶奶的Target。
class BigWildWolfAdapter implements Grandma {
private BigWildWolf wolf;
public BigWildWolfAdapter(BigWildWolf wolf) {
this.wolf = wolf;
}
@Override
public void snore() {
wolf.bark();
}
@Override
public void sleep() {
wolf.sleep();
}
}
最後小紅帽就會敲門叫奶奶,這時就會聽到奶奶的打呼聲,跟想要模仿奶奶打呼的狼的叫聲。
class GrandmaHome {
void call (Grandma grandma){
grandma.snore();
}
}
public class RedHat {
public static void main(String[] args) {
RedHatGrandma grandma = new RedHatGrandma();
BigWildWolf wolf = new BigWildWolf();
Grandma wolfAdapter = new BigWildWolfAdapter(wolf);
GrandmaHome home = new GrandmaHome();
home.call(grandma);
home.call(wolfAdapter);
}
}
output
Grandma snore
BigWildWolf bark
BigWildWolf imitate Grandma snore
在Client中,有奶奶(RedHatGrandma)跟假扮成奶奶的大野狼(BigWildWolfAdapter)。小紅帽執行home.call()的動作,分別傳回奶奶跟大野狼的聲音。可以看到,大野狼成功的假扮成奶奶了!
轉接器模式將一個類別的介面轉換成客戶希望的另外一個介面,Adapter使得原本由於介面相容而不能一起工作的那些類別可以一起工作
Target:想要變成的對象。(國外的插座)
Adaptee:想變身的對象。(繫帶的電器插頭)
Adapter:把想變身的對象變成他想變成的對象,這邊稱他上帝。(繫帶的轉接器)
優點
1. 可以讓沒有關聯的類別一起執行。
2. 提高類別的重用性。
3. 整體靈活度高。
缺點
1. 若使用過多的Adapter會使系統過於複雜凌亂,不易維護。
範例1:Object Adapter
範例2:Class Adapter(python)
範例3:Class Adapter(java)
範例4:Adapter Pattern
轉接器模式(Adapter Pattern)
轉接器模式 (Adapter Pattern)
Adapter pattern
Adapter 模式 - Class Adapter