קוד לדוגמה:
נעבור בסקירה קצרה על הדוגמה של class adapter ו object adapter עבור הדוגמה מהתחלת הפרק עם המחלקות Shape ו TextView:
class Shape {
public:
Shape();
virtual void BoundingBox (
Point& bottomLeft, Point& topRight
) const;
virtual Manipulator* CreateManipulator () const;
};
class TextView {
public:
TextView();
void GetOrigin(Coord& x, Coord& y) const;
void GetExtent(Coord& width, Coord& height) const;
virtual bool IsEmpty() const;
};
Shape מניחה שה bounding box מוגדרת על ידי שתי פינות נגדיות שלה. בניגוד לכך, TextView
מוגדרת על ידי נקודת ראשית, גובה ורוחב. כמו כן Shape מגדירה פעולת CreateManipulator()
שיוצרת אובייקט Manipulator שיודע לשנות אותה בתגובה לקלט מהמשתמש, כמו למשל גרירה עם עכבר, שינוי גודל וכו'. ב TextView
אין פעולה מקבילה. המחלקה TextShape היא adapter בין הממשקים השונים האלה.
Class adapter משתמש בהורשה מרובה לצורך ביצוע אדפטציה בין ממשקים. כפי שראינו הוא יורש ממחלקה אחת את הממשק (public) וממחלקה שניה את המימוש (privet):
class TextShape : public Shape, private TextView {
public:
TextShape();
virtual void BoundingBox (
Point& bottomLeft, Point& topRight
) const;
virtual bool IsEmpty() const;
virtual Manipulator* CreateManipulator() const;
};
נשים לב למספר נקודות:
נממש את פעולת ה BoundingBox() כך שתבצע אדפטציה מהממשק של TextView לממשק של
Shape (תפקידה הוא לעדכן שתי נקודות שהיא מקבלת by reference בפינות הקופסה החוסמת את הצורה. כאן היא עושה זאת תוך שימוש במימוש המוכן של
TextView):
void TextShape::BoundingBox (
Point& bottomLeft, Point& topRight
) const {
Coord bottom, left, width, height;
GetOrigin(bottom, left);
GetExtent(width, height);
bottomLeft = Point(bottom, left);
topRight = Point(bottom + height, left + width);
};
פעולת ה IsEmpty() מדגימה העברה ישירה של פקודה הלאה, דבר שמקובל במימוש של adapter- ים:
bool TextShape::IsEmpty () const {
return TextView::IsEmpty();
}
לבסוף, נגדיר את CreateManipulator() , פעולה שאינה נתמכת על ידי
TextView. נניח שכבר יש לנו מחלקה TextManipulator
שיודעת לשנות אובייקט TextShape:
Manipulator* TextShape::CreateManipulator () const {
Return new TextManipulator (this);
}
לעומת ה class adapter שראינו, ה object adapter משתמש בהרכבת אובייקטים כדי לבצע אדפטציה בין ממשקים. בגישה זו, ה adapter (
TextShape ) יחזיק פוינטר ל TextView:
class TextShape : public Shape {
public:
TextShape(TextView*);
virtual void BoundingBox(
Point& bottomLeft, Point& topRight
) const;
virtual bool IsEmpty() const;
virtual Manipulator* CreateManipulator() const;
private:
TextView* _text;
};
TextShape חייב לאתחל פוינטר לאובייקט TextView והוא עושה זאת בconstructor . הוא גם קורא לפעולות של האובייקט
TextView בכל פעם שקוראים לפעולות שלו. בדוגמה זו נניח שה client יוצר אובייקט מסוג TextView
ומעביר את זה ל constructor של TextShape:
TextShape::TextShape (TextView* t) {
_text = t;
}
void TextShape::BoundingBox (
Point& bottomLeft, Point& topRight
) const {
Coord bottom, left, width, height;
_text->GetOrigin(bottom, left);
_text->GetExtent(width, height);
bottomLeft = Point(bottom, left);
topRight = Point(bottom + height, left + width);
}
bool TextShape::IsEmpty () const {
return _text->IsEmpty();
}
המימוש של CreateManipulator() יהיה כמו במקרה הקודם מכיוון שאינו קשור ל
TextView, אלא הוא הרחבה שמגיעה מ Shape.
ה object adapter הוא מעט יותר ארוך לכתיבה, אבל יותר גמיש וקל לשינויים. למשל, הוא יעבוד גם עם subclasses של
TextView בניגוד ל class adapter - הפוינטר Text מוכן לקבל אותם כצאצאים של TextView.