אין תגובות

Adapter זה Design Pattern  מאוד פשוט ששיך למשפחת ה Structural Design Patterns, כלומר, אלו תבניות עיצוב שהמטרה שלהם היא לטפל במבנה הפנימי של הקוד שלנו וביחסים בין האובייקטים השונים, וכשמו כן הוא – מתאם.

 

בעולם האמיתי אנו משתמשים במתאמים כדי להצליח לעבוד עם כלי מסויים במערכת מסוג דומה אבל שונה. למשל, כאשר אנחנו מזמינים מוצר מחו"ל והוא מגיע עם תקע אמריקאי, אנחנו צריכים מתאם לשקע האירופאי שבבתים שלנו.

 

 

בקוד הדבר יבוא לידי ביטוי במקרים שבהם יש לי שתי מערכות שצריכות לדבר האחת עם השניה, אלא שלא בהכרח המתודות שלהן והמאפיינים שלהן זהים.

דוגמא: נניח שיש לי מערכת שמוכרת מוצרים, ובחישוב הכללי היא צריכה להדפיס את שם המוצר ואת מחירו. לצורך כך יהיה אינטרפייס עם המתודות הבאות:

  1. GetItemName

  2. GetItemPrice

כל מוצר במערכת שלנו צריך לקבל ייצוג בקלאס משלו שמממש את האינטרפייס הזה.

אמנם יתכן שתיווצר בעיה אם חלק מהקלאסים האלה אינם קלאסים שלנו או שהם ישנים ואין אפשרות לגעת בהם בגלל כל מיני תלויות.

כלומר, עדיין יהיו למוצרים האלה מתודות שמביאות מחיר ושם, אך יתכן שהן ממומשות אחרת. למשל GetShortName  ו GetPrice.

על מנת לפתור את הבעיה הזו נייצר קלאס שנקרא ProductNameAdapter והוא יורש מהאינטרפייס שלנו. בקונסטרקטור שלו הוא מקבל מופע של המוצר הספציפי שאותו הוא מייצג ובמימוש של המתודות הוא פונה למתודות הרלוונטיות במוצר שאותו הוא עוטף. וכך, אם לדוגמא המוצר שלנו הוא חולצה אזי במקום להוסיף לסל הקניות שלנו Shirt נוסיף ShirtAdapter.

הקוד יראה כך:

Interface:

   1: public interface Item

   2: {

   3:   string ItemName();

   4:   int ItemPrice();

   5: }

הקלאס הישן או ה’לא מתאים’ יראה למשל כך:

Class:

   1: public class Shirt

   2: {

   3:     private static double VAT_PERCENT = 0.2;

   4:     private String shortName;

   5:     private String longName;

   6:     private int basePrice;

   7:  

   8:     public Shirt(String shortName, String longName, int price)

   9:     {

  10:         this.shortName = shortName;

  11:         this.longName = longName;

  12:         basePrice = price;

  13:     }

  14:  

  15:     public String GetShortName()

  16:     {

  17:         return shortName;

  18:     }

  19:  

  20:     public String GetLongName()

  21:     {

  22:         return longName;

  23:     }

  24:  

  25:     public int GetPrice()

  26:     {

  27:         return (int)(basePrice * (1 + VAT_PERCENT));

  28:     }

  29: }

 

והמתאם, ה-Adapter יראה כך:

Adapter:

   1: public class ShirtAdapter : Item

   2: {

   3:    private Shirt shirt;

   4:  

   5:    public ShirtAdapter(Shirt shirt)

   6:    {

   7:        this.shirt = shirt;

   8:    }

   9:  

  10:    public String ItemName()

  11:    {

  12:        return shirt.GetShortName();

  13:    }

  14:  

  15:    public int ItemPrice()

  16:    {

  17:        return shirt.GetPrice();

  18:    }

  19: }

 

כעת הקליינט יוכל להשתמש במתודות של Item באופן רגיל, למרות שבאמת הקלאס Shirt אינו מממש באופן מדוייק את המתודות שלו, וזאת בזכות ה Adapter.

דוגמא לקליינט:

   1: public class ShoppingCart

   2: {

   3:    private List<Item> items = new List<Item>();

   4:  

   5:    public void Add(Item item)

   6:    {

   7:        items.Add(item);

   8:    }

   9:  

  10:    public bool Remove(Item item)

  11:    {

  12:        return items.Remove(item);

  13:    }

  14:  

  15:    public long GetTotalPrice()

  16:    {

  17:        long result = 0;

  18:        foreach (var item in items)

  19:        {

  20:            result += item.ItemPrice();

  21:        }

  22:        return result;

  23:    }

  24:  

  25:    public String GetReceipt()

  26:    {

  27:        StringBuilder result = new StringBuilder();

  28:        foreach (var item in items)

  29:        {

  30:            result.Append(item.ItemName() + "\t" + item.ItemPrice() + "\n");

  31:        }

  32:        return result.ToString();

  33:    }

  34: }

 

את הקוד בשלמותו ניתן להוריד כאן.

הוסף תגובה " class="ir icon-in">linkedin twitter email