# Adapter Pattern

เจ้าตัวนี้ผมขอตั้งชื่อเป็นภาษาไทยว่า **ผู้เชื่อมสัมพันธ์** ละกัน ซึ่งมันอยู่ในกลุ่มของ [**🧱 Structural Patterns**](https://www.saladpuk.com/beginner-1/design-patterns/structural) โดยเจ้าตัวนี้จะมาช่วยแก้ปัญหาเมื่อ **เรามีของ 2 อย่างที่ทำงานด้วยกันได้ค่อนข้างยาก แต่เราก็อยากให้มันทำงานด้วยกันได้โดยไม่ทำให้โค้ดเราซับซ้อนเกินไป** พูดแล้วก็ งงๆ ไปดูโจทย์ของเรากันเลยดีกว่าจะได้เข้าใจได้เร็วขึ้น

{% hint style="info" %}
**แนะนำให้อ่าน**\
บทความนี้เป็นส่วนหนึ่งของมหากาพย์ **Design Patterns** ที่จะมาเป็น guideline ในการแก้ปัญหาในการออกแบบซอฟต์แวร์โปรเจค หากใครสนใจอยากเข้าใจตั้งแต่ต้นว่ามันคืออะไร และเจ้า patterns ทั้ง 23 ตัวมีอะไรบ้าง ก็สามารถจิ้มตรงนี้เพื่อไปอ่านบทความหลักได้เบยครัช [👦 **Design Patterns**](https://saladpuk.gitbook.io/learn/beginner-1/design-patterns)
{% endhint %}

{% hint style="warning" %}
**หมายเหตุ**\
เนื้อหาของบทความนี้จะเน้นให้เข้าใจหลักการทำงานของ Design Patterns แต่ละตัว โดยภาพจากเกม Ragnarok เป็นการอธิบาย ซึ่งหลายๆอย่างนั้นมโนขึ้นมาเพื่อความสนุก และทำให้เข้าใจเนื้อหาได้ง่าย  *Gravity อย่ามาจับผมนะผมโดนแมวน้ำครอบงำ + รู้เท่าไม่ถึงการ + ผมเป็นคนดี + ผมมีลูกมีเมียมีสามีที่ต้องดูแล* 😭
{% endhint %}

## 🧐 โจทย์

สมมุติว่าเรารับงานเว็บทายผลบอลทุกคู่ทั่วโลกเพื่อความบันเทิงมา (ไร้ซึ่งการพนันใดๆทั้งสิ้น 🤐) โดยเมื่อบอลแข่งเสร็จ ตัวเว็บของเราก็ต้องไปดึงผลการแข่งขันจาก Web API ชั้นนำ 2 แห่งนั่นคือ **LongOnGoal, LifeScore** ตามรูปด้านล่าง

![](https://479516123-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lm0_idNbY6k1lwp6hm4%2F-MLD0ZWduQPaCgJYvoJo%2F-MLDF3WL2mKZla5o1Evn%2Fimage.png?alt=media\&token=58ce0fbe-79ea-4287-9f67-3d4690f437a0)

> 🤔 ทำไมต้องดึงมาจากหลายเว็บเหรอ? ก็**บางเว็บมีผลการแข่งเฉพาะคู่เล็กๆ บางเว็บมีผลเฉพาะคู่ใหญ่ๆ** และบางทีเราก็อาจจะต้อง**ตรวจสอบว่าผลมันตรงกันหรือเปล่า** เพื่อที่จะได้จ่าย... เอ้ย ให้แต้มคนที่ทายถูกได้นั่นเอง 😅 (ส่วนแต้มต่อก็ ... ช่างมันเถอะ 🤐)&#x20;

เท่าที่อ่านๆมาก็เหมือนจะง่ายๆเนอะ แค่ไปดึง API จากเว็บ 2 ตัวมาก็จบแล้วชิมิ ไหนลองไปดู **API สำหรับ ดึงผลคะแนน** ของเขาดูดิ๊

![](https://479516123-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lm0_idNbY6k1lwp6hm4%2F-MLD0ZWduQPaCgJYvoJo%2F-MLDG6EKmtXdTaPj8DIo%2Fimage.png?alt=media\&token=3d1038c8-feb3-432a-966d-cb915f552697)

![](https://479516123-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lm0_idNbY6k1lwp6hm4%2F-MLD0ZWduQPaCgJYvoJo%2F-MLDG9PWzU6hVnjVPPH_%2Fimage.png?alt=media\&token=4d43788b-d430-47f7-bc8e-d4bc81a22a27)

🤯 บรึ๊ม!! แม้ว่าจะเป็นเว็บผลคะแนนบอลเหมือนกันแต่ **API เรียกใช้ไม่เหมือนกัน, parameters ต่างกัน, models ต่างกัน** แล้วแบบนี้เราจะเขียนโค้ดยังไงดีเนี่ย? 😵

## 🧒 แก้โจทย์ครั้งที่ 1

อย่าไปคิดเยอะดิ ก็เขียนๆมันไปเลยจะยากอะไร อย่างแรกเลยก็เขียนไปดึงข้อมูลกับ LongOnGoalAPI มาเก็บไว้ แล้วก็ดึงจาก LifeScoreAPI มา สุดท้ายก็เอา 2 ตัวนี้มาเทียบกันก็จบละนิ ป๊ะโถ่วววว

![](https://479516123-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lm0_idNbY6k1lwp6hm4%2F-MLDGfrEFsBun6sDPQ93%2F-MLDJF0fgY8hQ1O25Qk6%2Fimage.png?alt=media\&token=2a9ee8a8-d591-4c17-9eb7-aa511c029745)

```csharp
var result1 = longOnGoalAPI.GetMatchResult(1234);
var result2 = lifeScoreAPI.GetHistory(DateTime.Now, "ManU", "Liver");
```

🤔 ก็เหมือนจะง่ายนะ แต่เราลืมอะไรไปป่ะว่า **model ที่ได้กลับมามันไม่เหมือนกัน** แล้วจะเปรียบเทียบยังไงอ่ะ?

![](https://479516123-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lm0_idNbY6k1lwp6hm4%2F-MLDGfrEFsBun6sDPQ93%2F-MLDK-syL8e4qx2nh35S%2Fimage.png?alt=media\&token=46e4bfa8-038c-42d2-8c32-35be4a19b6bc)

😎 งั้นก็ขอเขียนโค้ดแปลง model ทั้ง 2 ตัวไว้ตรงนี้เลยละกัน จะได้เทียบกันได้ง่ายๆ ตามด้านล่าง

```csharp
var homeScoreFromResult1 = // หาคะแนนของทีมเหย้า จาก LongOnGoalAPI
var awayScoreFromResult1 = // หาคะแนนของทีมเยือน จาก LongOnGoalAPI

var homeScoreFromResult2 = // หาคะแนนของทีมเหย้า จาก LifeScoreAPI
var awayScoreFromResult2 = // หาคะแนนของทีมเยือน จาก LifeScoreAPI
```

จากโค้ดด้านบนก็ไม่ได้ทำอะไรผิดนะ แก้โจทย์ที่ของเราได้ตามปรกติเลย แต่มันจะเกิดอะไรขึ้นถ้า **เราเพิ่ม Web API ตัวที่ 3, 4, 5 ... เข้ามาล่ะ?** เราก็ต้องไปไล่แก้โค้ดใหม่ทุกครั้งอะดิ แถมยิ่งแก้ยิ่งพันกันเป็นสปาเก็ตตี้ขึ้นไปเรื่อย 😨

เพราะโค้ดของเรามันมีหลายอย่างที่ไม่ตรงหลักในการออกแบบที่ดี เช่น **SRP**, **OCP, DIP** ยังไงล่ะ

{% hint style="danger" %}
**Single-Responsibility Principle (SRP)**\
การออกแบบที่ละเมิดหลักในการออกแบบนี้จะทำให้ เวลาที่ Requirement เปลี่ยนมาทีนึง มันก็จมีโอกาสสูงมากที่การเปลี่ยนนั้นมันจะไปกระทบเจ้าสิ่งนั้น ทำให้เราต้องแก้ไขมัน ซึ่งผองเพื่อนอื่นๆที่มันดูแลอยู่นั้นไม่ได้เกี่ยวข้องเลยก็มีผลกระทบด้วยนั่นเอง ส่วนใครที่ลืมหรืออยากทบทวนเรื่อง SRP สามารถเข้าไปอ่านได้จากลิงค์นี้เบย [**Single-Responsibility Principle**](https://saladpuk.gitbook.io/learn/basic/solid/srp)
{% endhint %}

{% hint style="danger" %}
**Open & Close Principle (OCP)**\
การออกแบบที่ละเมิดหลักในการออกแบบนี้จะทำให้ทุกครั้งที่มีของใหม่ๆถูกเพิ่มเข้าไปปุ๊ป เราก็ต้องไปแก้โค้ดเดิมเสมอ สำหรับใครที่ลืมหลักในการออกแบบเรื่องนี้ไปแล้วให้กดอ่านได้จากตรงนี้ [**Open & Close Principle**](https://saladpuk.gitbook.io/learn/basic/solid/ocp)
{% endhint %}

{% hint style="danger" %}
**Dependency-Inversion Principle (DIP)**\
การละเมิดกฎข้อนี้จะทำให้ module หลักต้องถูกแก้ไขบ่อยๆ เมื่อตัวที่ทำงานตัวเล็กตัวน้อยมีการเปลี่ยนแปลง แม้จะเปลี่ยนเพียงแค่เล็กน้อยก็ตาม [**Dependency-Inversion Principle**](https://www.saladpuk.com/basic/solid/dip)
{% endhint %}

🥴 อาวล่ะแม้ว่ามันจะมีปัญหาในอนาคตก็ตาม แต่อย่างน้อยเราก็ได้เห็นตัวอย่างในการบ้าพลัง เห็นโจทย์แล้วเมากาวกระโดดลงโค้ดเลย ผลก็คือ Design แบบกาวๆเหล่านั้นจะมีปัญหาในอนาคตนั่นเอง งั้นเดี๋ยวลองวางสมอง แล้วเติมน้ำหอมกันหน่อย เพื่อวิเคราะห์ปัญหาแล้วหาทางแก้ไขกันต่อ

## 🧒 แก้โจทย์ครั้งที่ 2

### 🔥 วิเคราะห์ปัญหา

โจทย์ในรอบนี้ไม่ได้ซับซ้อนอะไรเลย แต่ความยากของมันกลับไปตกอยู่ที่ **งานที่ต้องเชื่อมกับคนอื่น** หรือตัว Web API ต่างๆเพราะ **มันเป็นสิ่งที่เราควบคุมไม่ได้ว่าเขาจะออกแบบมายังไง หรือ เขาจะเปลี่ยนแปลงแก้ไขเมื่อไหร่**

{% hint style="danger" %}
🐲 **ควบคุมไม่ได้**\
เมื่อมีของที่เราควบคุมไม่ได้อยู่ในระบบของเราความบรรลัยก็จะบังเกิด เพราะ **วันดีคืนดีอยู่ๆของพวกนั้นเกิดใช้งานไม่ได้ หรือพฤติกรรมมันเปลี่ยนขึ้นมา ต่อให้โค้ดฝั่งเราเขียนดีแค่ไหนก็ตามก็ย่อมมีผลกระทบตามมา** หลายคนอาจจะคิดว่าเป็นของไกลตัวโปรเจคเราไม่มีของพวกนั้นหรอก งั้นแมวน้ำถามกลับว่า โปรเจคเราได้ใช้ Library ของคนอื่นป่ะ? ซึ่งของพวกนั้นดูเหมือนจะไม่มีพิษมีภัยอะไร แต่จริงๆมันก็คือของที่เราควบคุมไม่ได้แบบหนึ่งเหมือนกัน ลองศึกษา Case Study ด้านล่างต่อละกันถ้าสนใจ
{% endhint %}

{% hint style="info" %}
**Case Study**\
มี Library หลายตัวที่แมวน้ำใช้มาหลายปีก็ไม่มีปัญหาอะไร เช่น [**SimpleInjector**](https://simpleinjector.org/)**,** [**SendGrid**](https://sendgrid.com/) แต่พอมาถึงวันนึงที่เราต้องอัพเกรดเวอร์ชั่นปุ๊ป สิ่งที่เกิดขึ้นกับ **SimpleInjector** นั้นดูเหมือนไม่มีอะไรโค้ด compile ได้ไม่มีปัญหาแต่พฤติกรรมของมันเปลี่ยนไป ทำให้ life-cycle ของแอพผิดปรกติ นั่งหากันยกใหญ่ ส่วนเจ้า **SendGrid** ก็แสบไม่แพ้กัน พี่แกเล่นลบ core interface หลักทิ้ง แล้วไปขึ้น core interface ใหม่โดยไม่เหลืออันเดิมให้ใช้เลย (ปรกติเขาจะไม่ลบทิ้ง แต่จะใส่ obsolete attribute ไว้) ทำให้เราต้องมานั่งเสียเวลา re-implement ใหม่ หรือ Library บางตัวออกอัพเดทใหม่ก็มี bugs แถมมาด้วย\
\
😒 แต่ทั้งหมดจะไปโทษเขาก็ไม่ได้หรอก เราในฐานะ Developer ต้องตรวจของที่จะเอามาใช้งานใน production ก่อนเสมอแหละ (อย่าให้ผู้ใช้มาเป็นเทสเตอร์ให้เราเลย 😂)
{% endhint %}

### 🔥 แก้ไขปัญหา

**เมื่อเรามีของที่เราควบคุมไม่ได้ เราต้องเปลี่ยนเป็นสิ่งที่เราควบคุมได้ก่อน** เพราะไม่อย่างนั้นสนุกแน่ ซึ่งการที่เราจะไปควบคุมของอื่นๆมีหลายวิธีเลย ซึ่งวิธีง่ายสุดคือการทำ **Wrapper Class** โดยเราจะสร้างคลาสขึ้นมาครอบของที่ควบคุมไม่ได้เอาไว้ แล้วเราก็ทำงานกับคลาสตัวนั้นแทนที่จะทำงานกับของที่ควบคุมไม่ได้นั่นเอง ตามรูปด้านล่าง

> Design Pattern ที่มีลักษณะเป็น Wrapper Class มีหลายตัวเลย เช่น [**Proxy**](https://www.saladpuk.com/beginner-1/design-patterns/structural/proxy-pattern), Decorator ลองไปศึกษาต่อได้

![](https://479516123-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lm0_idNbY6k1lwp6hm4%2F-MLG4NT7IsyFe1fZU_VL%2F-MLG6JUG2xB2dJdGvOip%2Fimage.png?alt=media\&token=03ecb0b0-c929-4260-8e27-6a40fc06bd45)

โดยปรกติ **Wrapper Class จะมีหน้าที่เพียงแค่เรื่องเดียวคือควบคุมสิ่งที่มันดูแลอยู่** ดังนั้นเรื่องการจัดการ Web API ทั้ง 2 ตัวนั้น เราก็จะมี Wrapper Class เอาไว้ดูแลมันโดยเฉพาะเลย ตามรูปด้านล่าง

![](https://479516123-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lm0_idNbY6k1lwp6hm4%2F-MLG78Q6VGGFHasDXGyg%2F-MLIILfX4SMh4irARo_1%2Fimage.png?alt=media\&token=522d89d7-2216-4bea-a59a-d53dda0cb4f7)

ถัดมาเรื่องการใช้ Web API ทั้ง 2 ตัว แม้ว่ามันจะต่างกันคนละโลกแค่ไหนก็ตาม แต่ถ้าลองคิดดูดีๆเราก็จะพบว่า ของที่เราอยากได้จากมันจริงๆนั้นคือคะแนนการแข่งขันระหว่าง 2 ทีม ดังนั้น**จริงๆเราไม่ต้องสนใจด้วยซ้ำว่า API พวกนั้นจะส่ง model หน้าตาแบบไหนกลับมา ขอแค่เราสามารถแปลง model พวกนั้นให้กลายเป็นของที่เราสนใจได้ก็พอ** ตามรูปด้านล่าง

![](https://479516123-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lm0_idNbY6k1lwp6hm4%2F-MLG78Q6VGGFHasDXGyg%2F-MLIN6abrI_TDJ4mMmAD%2Fimage.png?alt=media\&token=6aa55a8f-dff3-424c-9897-76f5edde07c6)

ส่วนเรื่องที่ API ทั้ง 2 ตัวมันมีวิธีเรียกใช้ไม่เหมือนกัน ซึ่งถ้าคิดดูดีๆก็จะพบว่า **หน้าที่ในการดูแล API มันไปตกอยู่กับพวก Wrapper ดังนั้นหน้าที่ในการจัดการความซับซ้อนของ API เลยเป็นหน้าที่ของ Wrapper จึงทำให้เราเลือกได้เลยว่าเราอยากให้ Wrapper มีหน้าตาเป็นยังไง** นั่นเองตามรูป&#x20;

![](https://479516123-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lm0_idNbY6k1lwp6hm4%2F-MLG78Q6VGGFHasDXGyg%2F-MLIS7QNxK4Kzdl-GR9G%2Fimage.png?alt=media\&token=8aef0924-0846-41f6-b239-5bf73b8cdede)

พอมันกลายเป็นแบบรูปด้านบนปุ๊ป เราก็จะพบว่า Wrapper ของเราไม่มีความต่างละ ดังนั้นเราก็สามารถจัดการมันในรูปแบบของ interface ได้เลย ตามรูปด้านล่าง

![](https://479516123-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lm0_idNbY6k1lwp6hm4%2F-MLG78Q6VGGFHasDXGyg%2F-MLIV1pkx2OSXjipPVuP%2Fimage.png?alt=media\&token=e62c47db-11ad-4c9d-9883-940183d42592)

🤠 จากที่ว่ามาทั้งหมดปัญหาเรื่อง เวลาของที่เราควบคุมไม่ได้มีการเปลี่ยนแปลง มันก็จะกระทบแค่ Wrapper ที่ดูแลสิ่งนั้นอยู่เท่านั้น เพราะตัว Wrapper รับผิดชอบการดูแลไปแล้วนั่นเอง ซึ่งก็จะตรงกับกฎของ [**Single-Responsibility Principle**](https://saladpuk.gitbook.io/learn/basic/solid/srp) เรียบร้อย

![](https://479516123-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lm0_idNbY6k1lwp6hm4%2F-MLG78Q6VGGFHasDXGyg%2F-MLIX5I55jANDlgAfFkY%2Fimage.png?alt=media\&token=285f3642-80be-4db9-9aab-cfdf19132cc4)

🤠 หรือเราจะไปดึงข้อมูลจาก Web API อื่นๆ โค้ดเดิมก็ไม่มีผลกระทบอะไรเลย เพราะเราก็แค่เพิ่ม Adapter ตัวใหม่เข้าไป ซึ่งตรงกับกฎของ [**Open & Close Principle**](https://saladpuk.gitbook.io/learn/basic/solid/ocp) เรียบร้อย

![](https://479516123-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lm0_idNbY6k1lwp6hm4%2F-MLG78Q6VGGFHasDXGyg%2F-MLIYLuQa1nRKlv91hdP%2Fimage.png?alt=media\&token=97e4a22c-f555-4082-add1-6320c0e7ec4a)

🤠 และสุดท้ายต่อให้เราจะเลิกใช้ Web API ตัวไหนไป หรือเรามีการแก้ไข Web API นิดๆหน่อยก็จะไม่มีผลกระทบกับ module หลักที่เรียกใช้ Adapter เหล่านี้แล้ว ซึ่งก็ตรงกับกฎ [**Dependency-Inversion Principle**](https://www.saladpuk.com/basic/solid/dip) เช่นกัลล์

![](https://479516123-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lm0_idNbY6k1lwp6hm4%2F-MLG78Q6VGGFHasDXGyg%2F-MLIZA7_SsjFyk8POMhn%2Fimage.png?alt=media\&token=3eb9a7eb-82ec-4f5c-b92d-d5cb4040edf3)

ยินดีด้วยในตอนนี้คุณได้ใช้สิ่งที่เรียกว่า **Adapter Pattern** เรียบร้อยแล้ว ไม่ว่าจะรู้ตัวหรือไม่ก็ตาม เย่ๆ 👏

## 🤔 Adapter Pattern คือไย ?

มันคือ **แนวคิดในการแก้ปัญหาตอนที่เรามีของ 2 อย่างที่ทำงานร่วมกันไม่ได้หรือทำได้ยาก แต่เราก็อยากให้มันทำงานด้วยกันได้โดยไม่ทำให้โค้ดเราซับซ้อนเกินไป** ซึ่งในโลกความเป็นจริงเราก็จะเห็น Adapter Pattern ได้จากที่ชาร์จโทรศัพท์ไง เพราะเครื่องบางยี่ห้อจะรับเฉพาะ **Lightning** บางยี่ห้อรับเฉพาะ **Micro USB** บางอันเป็น **USB-C** ดังนั้นหน้าที่ของ Adapter Pattern ก็คือการแปลง ของที่เข้ากันไม่ได้ ให้ลงรอยกันได้นั่นเอง ตามรูปด้านล่าง

![](https://479516123-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lm0_idNbY6k1lwp6hm4%2F-MLIaH_O-pXlOeJi3TPN%2F-MLIi99_jcSFmNpG0l-7%2Fimage.png?alt=media\&token=c086236f-f70c-4092-bb67-88e0d00e3565)

ดังนั้นเมื่อไหร่ก็ตามที่เราเจอปัญหาเข้ากันไม่ได้ ให้รู้ได้เลยว่า Adapter Pattern อาจจะเป็นหนึ่งในทางออกของเราก็ได้

### 💡 หลักในการคิด

เมื่อไหร่ก็ตามที่เราเจอของ 2 อย่างที่มีการทำงานแตกต่างกัน เราก็แค่สร้างมาตรฐานใหม่ที่จะเอามากำกับดูแลของพวกนั้น ให้มันทำงานตรงตามสิ่งที่เราอยากได้ก็พอ ซึ่งในตัวอย่างของเราได้สร้างมาตรฐานใหม่ที่ชื่อว่า IFootballAdapter เอาไว้กำกับดูแลการทำงานของ Web API ทั้งหลายนั่นเอง

{% hint style="info" %}
**หมายเหตุ**\
โดยปรกติตัวมาตรฐานใหม่ที่เราสร้างขึ้นมาเราจะเรียกมันว่า **Adapter** ส่วนตัวที่ถูก adapter ดูแลอยู่ เราจะเรียกมันว่า **Adaptee**
{% endhint %}

🤠 การนำ Adapter ไปใช้งานนั้น สามารถออกแบบได้เยอะมาก ไม่ได้จำกัดว่าจะต้องเหมือกับในตัวอย่าง เช่นการทำ **Class Adapter Pattern**, **Object Adapter Pattern**

![Object Adapter Pattern (Wikipedia)](https://479516123-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lm0_idNbY6k1lwp6hm4%2F-MLIaH_O-pXlOeJi3TPN%2F-MLIccO3mfBlx9st4fFu%2Fimage.png?alt=media\&token=418b2eb5-4cb8-4e44-a812-da24994eb2dd)

![Class adapter Pattern (Wikipedia)](https://479516123-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lm0_idNbY6k1lwp6hm4%2F-MLIaH_O-pXlOeJi3TPN%2F-MLIdnPqkFMbj0_5KPLY%2Fimage.png?alt=media\&token=7c791e48-8002-4454-af57-d6fa6788ccb2)

{% hint style="success" %}
**เกร็ดความรู้**\
Class Adapter Pattern นั้นถูกออกแบบมาสำหรับภาษาที่รองรับการทำ multi-inheritance ก็จริง แต่ก็ไม่ได้หมายความว่าภาษาที่ไม่รองรับ multi-inheritance จะทำไม่ได้นะ เพราะเราสามารถทำ implement interface ได้หลายตัว
{% endhint %}

### 😎 Perfect Adapter

เมื่อเราสามารถแปลงข้อมูลจากฝั่ง A ไปหาฝั่ง B ได้ ในทฤษฎีของ Adapter Pattern นั้นก็ยังบอกอีกว่า เราก็ควรทำให้เจ้า Adapter สามารถแปลงข้อมูลกลับจากฝั่ง B ไปหาฝั่ง A ได้ด้วยเช่นกัน

![ส่งข้อมูลไปกลับได้ทั้ง 2 ฝั่ง](https://479516123-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lm0_idNbY6k1lwp6hm4%2F-MLIaH_O-pXlOeJi3TPN%2F-MLIgKKrqHPGvE573lup%2Fimage.png?alt=media\&token=957b723f-24f0-4db1-8ca0-fc293255d8b8)

## 🎯 บทสรุป

### 👍 ข้อดี

การนำ **Adapter Pattern** มาใช้งานนั้นจะช่วย ลดการผูกกันของโค้ดลง เพราะเราไม่ต้องไปวุ่นวายกับ Concrete class ที่อาจเปลี่ยนแปลงภายหลังได้ แถมจะเพิ่มจะลบ Adapter ตัวไหนก็สามารถทำได้เลยอีกด้วย

### 👎 ข้อเสีย

**เพิ่มความซับซ้อนโดยไม่จำเป็น** เพราะการนำ Adapter ไปใช้ จะทำให้เราไม่สามารถทำงานกับ Source ได้ตรงๆ

{% hint style="danger" %}
**ข้อควรระวัง**\
**อย่านำ Adapter Pattern ไปใช้มั่วซั่ว** เพราะมันทำให้โค้ดของเราซับซ้อนขึ้นเยอะเลยแทนที่เราจะเรียกใช้จาก Source ได้ตรงๆ เราจะต้องทำผ่าน Adapter อีกทีหนึ่ง ดังนั้นให้ชั่งน้ำหนักให้ดีเสียก่อนว่าปัญหาที่เราเจออยู่นั้น มันวุ่นวาย เทสยาก โค้ดมันผูกกันอยู่เยอะหรือเปล่า ถ้าชั่งน้ำหนักแล้ว + มีเหตุผลที่เพียงพอที่จะใช้ก็จงใช้ให้สบายใจไปเถิด
{% endhint %}

{% hint style="success" %}
เกลียด ชอบ ถูกใจ อยากติดตาม อยากติชมแนะนำด่าทอ หรืออะไรก็แล้วแต่ (ห้ามมายืมเงิน) จิ้มลงมาที่เพจนี้ได้เลย [**Mr.Saladpuk**](https://www.facebook.com/mr.saladpuk) และจะเป็นประคุณอันล้นพ้นถ้ากด Like + Follow + Share ให้ด้วยขอรับ น้ำตาจิไหล 🥺
{% endhint %}

![ช่องทางสนับสนุนค่าอาหารแมวน้ำกั๊ฟ 😘](https://479516123-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lm0_idNbY6k1lwp6hm4%2F-MKNgXXMPEbIB6sQztG2%2F-MKNmp9HEqzREDsXrZ0H%2Fpromptpay.png?alt=media\&token=0829926b-41a7-48d1-a515-4dea42ac4c2a)
