/ OOD

[365 วันแห่งโปรแกรม #day52] Adapter pattern

วันที่ห้าสิบสองของ ‪#‎365วันแห่งโปรแกรม วันนี้เราจะคุยกันเรื่อง Adapter pattern


Adapter pattern

Adapter pattern เป็น Pattern แบบ Structural patterns ใช้แก้ปัญหาเรื่องความเข้ากันไม่ได้ของโมดูลใหม่กับ interface ของโมดูลที่มีอยู่แล้ว โดยสร้างตัวกลางขึ้นมาเชื่อมแทนที่จะแก้แก้ที่โค้ดของโมดูลนั้นๆ

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

ในแพทเทิร์นนี้มีโครงสร้างอยู่ 2 แบบ คือ Object Adapter pattern และ Class Adapter pattern

Object Adapter pattern

Object Adapter pattern คือรูปแบบของ Adapter pattern ที่ตัว Adapter นั้นเก็บ instance ของคลาสที่จะเชื่อมเอาไว้ แล้วตัว Adapter เองก็ derived มาจาก interface ที่โมดูลที่นำไปใช้ได้

The object adapter pattern expressed in UML

จาก diagram ข้างต้นจะเห็นว่า Client จะเรียกใช้งาน Adaptee (โมดูลที่จะเอามาเชื่อม) ผ่านทาง Adapter

The object adapter pattern expressed in LePUS3

Digram นี้แสดงให้เห็นชัดเจนว่าจริงๆ แล้ว Client ไม่ได้มองว่ากำลังคุยกับ Adapter อยู่ แต่มองว่าตัวเองกำลังคุยกับ Target module (โมดูลที่ Client ต้องการสื่อสารด้วย) อยู่ เพราะ Adapter ของเรานั้น derived มาจาก interface เดียวกันกับ Target module นั่นเอง

เมื่อ Client เรียกใช้ method ของ Target (Adapter) ตัว Adapter เองก็จะทำการเรียกใช้ method ของ Adaptee อีกที

Class Adapter pattern

Class Adapter pattern เป็นอีกรูปแบบหนึ่งของ Adapter pattern รูปแบบนี้จะใช้ Technic multiple polymorphic interfaces กับ Adapter กล่าวคือ Adapter จะทำการ Inherit มาจากทั้ง Target class และ Adaptee Class (โดยทั่วไปจะ inherit จาก abstraction ของ Target และ implementation ของ Adaptee)

The class adapter pattern expressed in UML

จาก Digram ข้างต้นจะเห็นว่า Adapter นั้น derived จะมาจาก Adaptee กี่คลาสก็ได้ (ถ้าภาษาโปรแกรมนั้นรองรับ multiple inheritance) เมื่อ Client เรียกใช้ method ของ Adapter ตัว Adapter ก็จะไปเรียก method อื่นที่ inherit มาอีกที (เว้นแต่กรณีที่ method ที่ Client เรียกนั้นมีอยู่แล้วใน Adaptee เราก็ไม่จำเป็นต้อง implement ใหม่)

The class adapter pattern expressed in LePUS3

Diagram นี้ทำให้เห็นภาพมากขึ้นว่า Client ยังคงคิดว่าตัวเองคุยกับ Target เหมือนเดิม เพราะ Adapter นั้น implement มาจาก Target

วิธีนี้มักจะใช้เมื่อ Adaptee class นั้นมี interface บางส่วนที่เหมือนกับ Target ซึ่งทำให้เราประหยัดเวลาในการ implement method ของ Target ใหม่ เพื่อไปเรียก method ของ Adaptee ได้พอสมควร

ตัวอย่างการนำไปใช้

สมมติว่าโปรแกรมของเรามีการใช้งานโมดูลสำหรับ generate string ที่ไม่ซ้ำกันเลย (unique string) อยู่ แล้ววันหนึ่งเราพบว่ามีคลาส generate string แบบเดียวกันที่คนอื่นเขียนไว้เป็น open source แต่มีประสิทธิภาพสูงกว่ามาก ก็เลยอยากย้ายไปใช้คลาสใหม่นั้น แต่ก็ไม่อยากไปรื้อโปรแกรมเพราะกลัวว่าจะเสีย ดังนั้นเราจึงต้องหาทางในการเชื่อมต่อกับ class ใหม่ โดยไม่แก้โค้ดหรือแก้ให้น้อยที่สุด

class StringRandom{
    public string Generate(){...}
}
class Program{
    public static void Main(string args...){
        StringRandom stringRandom = new StringRandom();
        string var1 = stringRandom.Generate();
        ...
    }
    ...
}

โค้ดข้างต้นนี้คือโปรแกรมเดิมซึ่งมีการขอค่าสุ่มจาก StringRandom ผ่าน method Generate() แต่ในคลาสใหม่นั้นไม่มี Generate() แล้ว ดังนี้

class QniqueString{
    public string Random(){...}
}

จะเห็นว่ามี method สำหรับสุ่ม string เหมือนกัน แต่ชื่อไม่เหมือนกัน (ถึงชื่อ method ทั้งหมดเหมือนกันก็เอามาใช้ไม่ได้อยู่ดี เพราะไม่ได้ derived มาจาก interface เดียวกัน) ดังนั้นเราจึงต้องสร้าง Adapter ขึ้นมาช่วย

class QniqueStringRandom : StringRandom{
    private QniqueString adaptee = new QniqueString();
    public string Generate(){
        return adaptee. Random();
    }
}

แล้เวก็เอาไปใช้ในโปรแกรมของเราได้เลยครับ (เปลี่ยนส่วน initialize ของ StringRandom เป็นสร้าง object ของ QniqueStringRandom แทน)

class Program{
    public static void Main(string args...){
        StringRandom stringRandom = new QniqueStringRandom();
        string var1 = stringRandom.Generate();
        ...
    }
    ...
}

เพียงเท่านี้เราโปรแกรมของเราก็สามารถทำงานร่วมกับโมดูลสุ่มค่าอันใหม่ได้แล้วครับ

References

Adapter pattern

Adapter Design Pattern

#‎day52 #365วันแห่งโปรแกรม ‪#‎โครงการ365วันแห่ง‬...