# Design Pattern - Adapter
## 前言
你是否曾經遇過辛辛苦苦開發了一個不錯的程式包,卻因為一點點的差異導致無法被重複應用。
這個差異可能是 5%、10%、20% 左右,但卻造成了整包東西無法被再次使用、整合的情境。
今天在專案中引用一個 A 服務,隔天被告知要更換成 B 服務,幾周後又要改成 C 服務,而來自 A B C 的服務本身或多或少都有差異,造成每一次的改變都必須更動到原本的程式邏輯才能完美契合。
但對於程式碼的維護來說卻是糟糕的處理方式,每一次的更正都必須要跑一次測試。
這就像過去有許許多多不同規格的電線插頭一樣,為了不同的插頭而去更換機械部件的插座,非常不符合效益。
今天要說到的 Adapter 正是後來出現的 "轉接頭",他實現了不同規格仍能對接的期望,避免需要更換插座或是更換插頭的狀況。
## 主題
**Adapter Pattern**
中文常見名稱 **建造者模式**
屬於 **Structural Design Pattern** 一種常見的設計理念。
目的是幫助工程師在對接服務的時候,避免需要動到對街服務本身的邏輯,從而避免了可能因改動造成的問題。確保了程式本身的獨立與完整。
**優點:**
- 底層邏輯與實務邏輯(Adapter層)職責分離,增加底層邏輯的重複使用性
- 符合 S.O.L.I.D 原則
- 高擴展性
**缺點:**
- 過度的使用 Adapter Pattern 會增加整體架構的複雜性與可維護性
- 較直接使用底層邏輯來的低效
- 測試的難度較高,錯誤的來源有更多的可能性
Adapter Design Pattern 又分為兩種:
- Object Adapter
- Class Adapter
## Object Adapter
透過實作指定 Interface 的 Adapter 類,並放入想要轉換的類方式實現調配

[圖片來源於 Adapter Design Pattern Wiki](https://en.wikipedia.org/wiki/Adapter_pattern)
## Class Adapter
透過多重繼承的方式進行調配,適用於 C++、Python,Java 因為不支援多重繼承,故需要改寫成繼承與實作並行的方式實現調配

[圖片來源於 Adapter Design Pattern Wiki](https://en.wikipedia.org/wiki/Adapter_pattern)
## 實行方式
```java=
public class Adapter {
public static void main(String [] args){
InitService1 service1 = new Service1Impl();
InitService2 service2 = new Service2Impl();
service1.service_1();
service1.service_2();
service2.service_3();
service2.service_4();
AdapterService1ToService2 adapterService = new AdapterService1ToService2(service1);
adapterService.service_3();
adapterService.service_4();
}
}
interface InitService1{
void service_1();
void service_2();
}
class Service1Impl implements InitService1{
@Override
public void service_1() {
System.out.println("This is Service 1 Service_1().");
}
@Override
public void service_2() {
System.out.println("This is Service 1 Service_2().");
}
}
interface InitService2{
void service_3();
void service_4();
}
class Service2Impl implements InitService2 {
@Override
public void service_3() {
System.out.println("This is Service 2 Service_3().");
}
@Override
public void service_4() {
System.out.println("This is Service 2 Service_4().");
}
}
class AdapterService1ToService2 implements InitService2 {
private InitService1 service1Impl;
public AdapterService1ToService2(InitService1 initService1){
this.service1Impl = initService1;
}
@Override
public void service_3(){
/* code ... */
System.out.println("This is Adapter.");
service1Impl.service_1();
/* code ... */
}
@Override
public void service_4(){
/* code ... */
System.out.println("This is Adapter.");
service1Impl.service_2();
/* code ... */
}
}
```
```
Execute Results:
This is Service 1 Service_1().
This is Service 1 Service_2().
This is Service 2 Service_3().
This is Service 2 Service_4().
This is Adapter.
This is Service 1 Service_1().
This is Adapter.
This is Service 1 Service_2().
```
範例中有 **InitService1**、**InitService2** 兩介面,與實作介面的實體 **Service1Impl**、**Service2Impl**
Kai 這邊建立一個將 Service1 轉為 Service2 的 Adapter 類別 **AdapterService1ToService2**,由於目標是轉成 Service2,故需實作 InitService2
除了實作介面的方法外,還包含將 Service1 放入的方法,在使用上就可以透過放入 Service1 的方式對接 Service2 的服務了
:::danger
用一句話介紹 Adapter Pattern: **一個轉接頭概念的設計模式**
:::
首頁 [Kai 個人技術 Hackmd](/2G-RoB0QTrKzkftH2uLueA)
###### tags: `Design Pattern`