Skeleton of GOF's Design Pattern


OBSERVERの骸骨

OBSERVER

複数の関連し合うオブジェクトの状態の一貫性を保つためのパターンです。

状態の基準となるオブジェクトを Subject(Observable) と呼び、Subject(Observavle) と関連をもつオブジェクトを Observer と呼びます。通常、Observer は複数になります。

関連しあうオブジェクトのどこかに変化が生じると、Subject は、その変化を関連する全ての Observer へ通知するのが、このパターンの特徴です。


■ 『OBSERVERの骸骨』の構造


■ 『OBSERVERの骸骨』の特徴的な協調関係


■ 『OBSERVERの骸骨』 プログラム・コード

□ Java2版
// Copyright(C) 2000-2003 Yoshinori Oota All rights reserved.

import java.util.*;

public class ObserverSample { 
    static public void main(String[] args) { 

        MsgSubject observable = new MsgSubject();
        MsgObserver a = new MsgObserver("yoshi", observable);
        MsgObserver b = new MsgObserver("chako", observable);

        a.message("Hello Everybody!");
        b.message("Good Bye Everybody!"); 
    } 
}

class Observable { 
    private LinkedList _observers = new LinkedList();

    public void addObserver(Observer observer) { 
        _observers.add(observer); 
    }

    public void notifyObservers(Object arg) { 
        ListIterator it = _observers.listIterator();
        while (it.hasNext()) {
            Observer observer = (Observer)it.next();
            observer.update(arg); 
        }
    }
}

class MsgSubject extends Observable { 
    public void write(String msg) { 
        notifyObservers(msg); 
    } 
}

abstract class Observer { 
    abstract public void update(Object arg);
}

class MsgObserver extends Observer {
    private String _id = null;
    private MsgSubject _observable = null;

    public MsgObserver(String id, MsgSubject observable) {
        _id = id;
        _observable = observable;
        _observable.addObserver(this);
    }
    public void message(String msg) {
        _observable.write("[" + _id + "'s msg] "  + msg);
    }
    public void update(Object arg) {
        System.out.println(_id + "> " + (String)arg);
    }
}

○ C++版
// Copyright(C) 2003 Yoshinori Oota All rights reserved.

#include <string>
#include <list>
#include <iostream>
using namespace std;

class Observable;
class Observer;
class MsgSubject;
class MsgObserver;

class Observable {
public:
    Observable();
    virtual ~Observable();
    void addObserver(Observer* o);
    void deleteObserver(Observer* o);
    void notifyObservers(const string& arg);
private:
    list<Observer*> observers_;
};

class MsgSubject : public Observable {
public:
    MsgSubject();
    virtual ~MsgSubject();
    void write(const string& msg);
};

class Observer {
public:
    Observer();
    virtual ~Observer();
    virtual void update(const string& arg) = 0;
};

class MsgObserver : public Observer {
public:
    MsgObserver(const string& id, MsgSubject* observable);
    virtual ~MsgObserver();
    virtual void update(const string& arg);
    void message(const string& arg);
private:
    string id_;
    MsgSubject* observable_;
    bool accessable_;
};


Observable::Observable() { }
Observable::~Observable() { }
void Observable::addObserver(Observer* o) {
    observers_.push_back(o);
}
void Observable::deleteObserver(Observer* o) {
    observers_.remove(o);
}
void Observable::notifyObservers(const string& arg) {
    list<Observer*>::iterator it = observers_.begin();
    while (it != observers_.end()) {
        (*it)->update(arg);
        ++it;
    }
}

MsgSubject::MsgSubject() { }
MsgSubject::~MsgSubject() { }
void MsgSubject::write(const string& msg) {
    notifyObservers(msg);
}

Observer::Observer() { }
Observer::~Observer() { }

MsgObserver::MsgObserver(const string& id, MsgSubject* o) : id_(id), observable_(o) {
    observable_->addObserver(this);
}
MsgObserver::~MsgObserver() {
    observable_->deleteObserver(this);
}
void MsgObserver::message(const string& arg) {
    string msg("");
    msg += "[";
    msg += id_;
    msg += "'s msg] ";
    msg += arg;
    observable_->write(msg);
}
void MsgObserver::update(const string& arg) {
    cout << id_ << "> " << arg << endl;
}


int main() {
    MsgSubject* observable = new MsgSubject();
    MsgObserver* a = new MsgObserver("yoshi", observable);
    MsgObserver* b = new MsgObserver("chako", observable);

    a->message("Hello Everybody!");
    b->message("Goodbye Everybody!");

    delete a;
    delete b;
    delete observable;
}

○ C版
/* Copyright(C) 2009 Yoshinori Oota All rights reserved. */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>


/* ObserverList Inteface */
struct ObserverList {
    struct Observer* observer_;
    struct ObserverList* next_;
};
struct ObserverList* New_ObserverList(struct Observer* observer);
void Delete_ObserverList(struct ObserverList* list);
void Delete_ObserverListAt(struct ObserverList* list);


/* Observer Interface */
struct Observer {
    char* id_;
    void (*update)(struct Observer* pthis ,const char* arg);
    void (*message)(struct Observer* pthis ,const char* arg);
};
struct Observer* New_Observer(const char* id);
void Delete_Observer(struct Observer* observer);
void Observer_update(struct Observer* pthis ,const char* arg);
void Observer_message(struct Observer* pthis ,const char* arg);


/* Observable Interface */
void Observable_addObserver(struct Observer* observer);
void Observable_deleteObserver(struct Observer* observer);
void Observable_private_notifyObservers(const char* arg);
void Observable_write(const char* arg);


/* ObeserList Implementation */
struct ObserverList* New_ObserverList(struct Observer* observer) {
    struct ObserverList* list = NULL;
    list = (struct ObserverList*)malloc(sizeof(struct ObserverList));
    list->observer_ = observer;
    list->next_ = NULL;
    return list;
}

void Delete_ObserverList(struct ObserverList* list) {
    struct ObserverList* tmp = NULL;
    if (list == NULL) {
        return;
    }
    while (list != NULL) {
        tmp = list->next_;
        free(list);
        list = tmp;
    }
    return;
}

void Delete_ObserverListAt(struct ObserverList* list) {
    if (list == NULL) {
        return;
    }
    free(list);
    list = NULL;
    return;
}


/* Observer Class Implementation */
struct Observer* New_Observer(const char* id) {
    struct Observer* observer = NULL;
    char* buf = NULL;
    observer = (struct Observer*)malloc(sizeof(struct Observer));
    buf = (char*)malloc(strlen(id)+1);
    strcpy(buf, id);
    observer->id_ = buf;
    observer->update = &Observer_update;
    observer->message = &Observer_message;
    return observer;
}

void Delete_Observer(struct Observer* observer) {
    if (observer == NULL) {
        return;
    }
    free(observer->id_);
    observer->id_ = NULL;
    free(observer);
    observer = NULL;
    return;
}

void Observer_message(struct Observer* pthis ,const char* arg) {
    char* msg = NULL;
    char* l = "[";
    char* r = "'s msg]";
    int len = 0;

    len = strlen(l)+strlen(pthis->id_)+strlen(r)+strlen(arg)+1;
    msg = (char*)malloc(len);
    strcpy(msg ,l);
    strcat(msg ,pthis->id_);
    strcat(msg ,r);
    strcat(msg ,arg);
    Observable_write(msg);
    return;
}

void Observer_update(struct Observer* pthis, const char* arg) {
    printf("%s> %s\n" ,pthis->id_, arg);
    return;
}


/* Observable Implementation */
struct ObserverList* gObserversTop = NULL;
struct ObserverList* gObserversLast = NULL;

void Observable_addObserver(struct Observer* observer) {
    struct ObserverList* list = NULL;
    list = New_ObserverList(observer);
    if (gObserversTop == NULL) {
        gObserversTop = list;
        gObserversLast = list;
    } else {
        gObserversLast->next_ = list;
        gObserversLast = list;
    }
    return;
}

void Observable_deleteObserver(struct Observer* observer) {
    struct ObserverList* cur = NULL;
    struct ObserverList* prv = NULL;

    if (gObserversTop == NULL) return;

    cur = gObserversTop;
    if (strcmp(cur->observer_->id_ ,observer->id_) == 0) {
        gObserversTop = gObserversTop->next_;  /* 先頭をはずす */ 
        Delete_ObserverListAt(cur); /* 先頭のリストを開放 */
        return;
    }

    while (cur != NULL) {
        prv = cur;
        cur = cur->next_;
        if (strcmp(cur->observer_->id_ ,observer->id_) == 0) {
            prv->next_ = cur->next_; /* 一つ前の要素と次の要素を連結 */
            Delete_ObserverListAt(cur);
            return;
        }
    }
    return;
}

void Observable_Clean() {
    Delete_ObserverList(gObserversTop);
    gObserversLast = NULL;
    return;
}

void Observable_private_notifyObservers(const char* arg) {
    struct ObserverList* cur = NULL;
    cur = gObserversTop;
    while (cur != NULL) {
        cur->observer_->update(cur->observer_ ,arg);
        cur = cur->next_;
    }
    return;
}

void Observable_write(const char* arg) {
    Observable_private_notifyObservers(arg);
    return;
}


int main() {
    struct Observer* a = New_Observer("yoshi");
    struct Observer* b = New_Observer("chako");

    Observable_addObserver(a);
    Observable_addObserver(b);

    a->message(a ,"Hello Everybody!");
    b->message(b ,"Goodbye Everybody!");

    Observable_deleteObserver(a);
    Observable_deleteObserver(b);

    Delete_Observer(a);
    Delete_Observer(b);

    Observable_Clean();

    return 0;
}


改訂履歴

2009.2.22 C言語版を追加
     
     

ご意見、ご感想はこちらまで。

Copyright(C) 2000-2009 Yoshinori Oota All rights reserved.

本ホームページのリンクは自由です。複製、転載される場合は、必ず著者までご連絡をください。