ראשי > observer pattern > חלק שלישי
The Observer

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

למעלה
קוד לדוגמה:
מחלקה אבסטרקטית מגדיר את הממשק של ה observer :

class Subject;

class Observer {
public:
     virtual ~Observer();
     virtual void Update(Subject* theChangedSubject) =
     0;
protected:
     Observer();
};

המימוש תומך במספר subject ים לכל observer. ה subject שמועבר לפעולת ה Update() מאפשר ל observer לקבוע באיזה subject התרחש השינוי במידה והוא צופה ביותר מאחד. באופן דומה יש class אבסטרקטי שמגדיר את ממשק ה subject:

class Subject {
public:
     virtual ~Subject();

     virtual void Attach (Observer*);
     virtual void Detach (Observer*);
     virtual void Notify();
protected:
     Subject();
private:
     List<Observer*> *_observers;
};

void Subject::Attach (Observer* o) {
     _observers->Append(o);
}

void Subject::Detach (Observer* o) {
     _observers->Remove(o);
}

void Subject::Notify () {
     ListIterator<Observer*> i(_observers);

     for (i.First(); !i.IsDone(); i.Next()) {
     i.CurrentItem()->Update(this);
     }
}

ClockTimer הוא concrete subject שמאחסן את הזמן הנוכחי. הוא מיידע את הobserver ים שלו על שינוי כל שניה. הוא מספק ממשק עבור קבלה של שעה, קבלה של דקה וקבלה של שניה.

class ClockTimer : public Subject {
public:
     ClockTimer();

     virtual int GetHour();
     virtual int GetMinute();
     virtual int GetSecond();

     void Tick();
};

פעולת ה Tick() נקראת על ידי טיימר פנימי ברווחים קבועים . Tick() מעדכנת את המצב הפנימי של ClockTimer וקוראת ל Notify() כדי ליידע את ה observer ים על שינוי:

void ClockTimer::Tick () {
     // update intermal time-keeping state
     // ...
     Notify();
}

כעת אפשר להגדיר את DigitalClock שיראה את השעה. נשתמש בהורשה מרובה. הוא יורש את הפונקציונליות הגרפית מ GraphicalElement שהוא אובייקט מוכן להצגה גרפית. הוא גם יורש מה Observer את הממשק של Observer:

Class DigitalClock: public GraphicalElement, public Observer {
public:
     DigitalClock (ClockTimer*);
     virtual ~DigitalClock();

     virtual void Update(Subject*);
         // overrides Observer operation

     virtual void Draw();
     // overrides GraphicalElement operation
     // defines how to draw the digital clock
private:
     ClockTimer* _subject;
};

DigitalClock::DigitalClock(ClockTimer* s) {
     _subject = s;
     _subject->Attach(this);
}

DigitalClock::~DigitalClock() {
     _subject->Detach(this);
}

לפני שפעולת ה Update() מציירת את מראה השעון היא בודקת שהאובייקט שהשתנה הוא אכן ה subject של ה clock:

void DigitalClock::Update(Subject* theChangedSubject) {
     if (theChangedSubject == _subject) {
         Draw();
     }
}

void DigitalClock::Draw () {
     // get the new values from the subject

     int hour = _subject->GetHour();
     int minute = _subject->GetMinute();
     // etc.

     // draw the digital clock
}

באותה צורה אפשר להגדיר AnalogClock:

class AnalogClock : public GraphicalElement, public Observer {
public:
     AnalogClock (ClockTimer*);
     virtual void Update (Subject*);
     virtual void Draw();
     // ...
};

הקוד הבא יוצר AnalogClock ו DigitalClock שמראים תמיד את אותו הזמן:

ClockTimer* timer = new ClockTimer;
AnalogClock* analogClock = new AnalogClock (timer);
DigitalClock* digitalClock = new DigitalClock (timer);

בכל פעם ש timer מתקתק (Tick()) שני השעונים יעודכנו ויראו את השעה האמיתית.

למעלה







 
מה בעמוד:
 
מימוש
קוד לדוגמה