Observer Pattern
ÃÑ ÆäÀÌÁö ¼ö : 3224

Àüü ÇÔ¼ö/¿ë¾î»çÀü
Facebook Joinc ±×·ì   Joinc QA »çÀÌÆ®



joinc´Â Firefox¿Í chrome¿¡¼­ Å×½ºÆ® Çß½À´Ï´Ù. IE¿¡¼­´Â Å×À̺íÀÌ ±úÁö°Å³ª À̹ÌÁö°¡ º¸ÀÌÁö ¾ÊÀ» ¼ö ÀÖ½À´Ï´Ù. ƯÈ÷ ±¸±Û DocsÀ̹ÌÁöÀÇ °æ¿ì ¿¢¹Úó¸®µÉ ¼ö ÀÖ½À´Ï´Ù.

¿ÉÀú¹ö ÆÐÅÏ

¿ÉÀú¹ö ÆÐÅÏÀº Publish subscribeÆÐÅÏÀ̶ó°í ºÒ¸®¿ì±âµµ ÇÑ´Ù. ÄÁÅÙÃ÷ ¹ßÇàÀÚ°¡ ÄÁÅÙÃ÷ÀÇ º¯È­°¡ »ý°åÀ» ¶§ ±¸µ¶ÀÚ¿¡°Ô ¾Ë·ÁÁÖ´Â ¹æ½Ä°ú ºñ½ÁÇϱ⠶§¹®ÀÌ´Ù.

ÀÌ ÆÐÅÏÀº °´Ã¼ÀÇ »óŸ¦ °üÂûÇÏ´Â Observer - °üÂûÀÚ -°´Ã¼°¡ Á¸ÀçÇÑ´Ù. ÀÌ Oserver´Â °´Ã¼ÀÇ »óŰ¡ ¹Ù²î¸é ±× °´Ã¼¿¡ ÀÇÁ¸°ü°è¿¡ ÀÖ´Â ´Ù¸¥ °´Ã¼µé¿¡°Ôµµ »óŰ¡ º¯°æµÇ¾úÀ½À» ¾Ë·ÁÁØ´Ù.

Observer-pattern-uml.jpg

subject class

Ãß»ó Ŭ·¡½º·Î observer¸¦ µî·ÏÇϰí Á¦°ÅÇϱâ À§ÇÑ ¸Þ¼­µåµéÀ» Á¦°øÇÑ´Ù. ¶ÇÇÑ À̺¥Æ®¸¦ Publish Çϱâ À§ÇÑ notify ¸Þ¼­µåµéÀ» °¡Áø´Ù.
  • Attach - »õ·Î¿î observer¸¦ µî·ÏÇÑ´Ù.
  • Detach - µî·ÏµÇ¾î ÀÖ´Â observer¸¦ »èÁ¦ÇÑ´Ù.
  • Notify - observer¿¡ ¹ß»ýÇÑ À̺¥Æ®ÀÇ Á¤º¸¸¦ Àü´ÞÇϱâ À§Çؼ­ »ç¿ëµÉ ¼ö ÀÖ´Ù.

Observer class

subjectÀÇ Notify¿¡ ÀÇÇØ¼­ È£ÃâµÉ ÄݹéÇÔ¼ö - °¡»ó ¸Þ¼­µå ȤÀº ÇÔ¼öÆ÷ÀÎÅÍ -¸¦ °¡Áø´Ù. ÀÌ ÄݹéÇÔ¼ö´Â À̺¥Æ®°¡ ¹ß»ýÇßÀ» ¶§ ó¸®ÇÒ ¾Ë°í¸®ÁòÀ» Æ÷ÇÔÇÑ´Ù.


ÀÀ¿ë

ÀÌ ÆÐÅÏÀº À¯Àú³ª ȤÀº ½Ã½ºÅÛÀ¸·Î ºÎÅÍÀÇ ÀԷ¿¡ ´ëÇÑ ÀÀ´äÀ» ÇØ¾ß ÇÏ´Â À̺¥Æ® ±â¹Ý ÇÁ·Î±×·¥¿¡ ³Î¸® »ç¿ëµÈ´Ù. ¶§¶§·Î MVC ¸ðµ¨°ú °áÇյǾ »ç¿ëÇÏ´Â °æ¿ìµµ ÀÖ´Ù. MVC ¸ðµ¨Àº ModelÀÇ º¯È­¿¡ µû¶ó¼­ Viewµµ º¯°æÀÌ µÇ´Â °æ¿ì°¡ »ý±â´Âµ¥, À̶§ Model ¿ÉÀú¹ö°¡ viewÀÇ ³»¿ëÀ» ¹Ù²Ù´Â ¹æ½ÄÀÌ´Ù.

MVC ¸ðµ¨

À¥¼­ºñ½º¿¡ MVC¸ðµ¨ÀÌ Àû¿ëµÈ °æ¿ì¶ó¸é url ÆÄ¶ó¸ÞÅ͸¦ °Ë»çÇÏ´Â model ¿ÉÀú¹ö¸¦ µÎ´Â °ÍÀ¸·Î ½±°Ô ÀÌ ¹®Á¦¸¦ ÇØ°áÇÒ ¼ö ÀÖÀ» °ÍÀÌ´Ù.

Event Àü´Þ

QT¿Í °°Àº GUIŸŶ¿¡ »ç¿ëµÇ´Â ½Ã±×³Î/½½·Ô ¸ðµ¨°ú message¸¦ ó¸®ÇÏ´Â ÇÁ·Î±×·¥µé

½Ã±×³Î ½½·Ô ¸ðµ¨ ȤÀº message¸¦ ó¸®ÇØ¾ß ÇÏ´Â ÇÁ·Î±×·¥¿¡ À־ÀÇ À̽´´Â busy wait¿¡ ³õÀÌÁö ¾ÊÀº »óÅ·ΠEventȤÀº message¸¦ ±â´Ù¸®´Â°Ô µÉ °ÍÀÌ´Ù. À̸¦ À§Çؼ­ ´Ù¾çÇÑ ¹æ¹ýÀÌ »ç¿ëµÉ ¼ö ÀÖÀ» °Çµ¥, ³ª´Â ÁÖ·Î ÆÄÀÏ·¹ÄÚµå Àá±ÝÀ» ÀÌ¿ëÇØ¼­ ÀÌ ¹®Á¦¸¦ ÇØ°áÇϰí ÀÖ´Ù. Observer°¡ Àá±ÝÀ» Ǫ´Â °ÍÀ¸·Î Notify¸¦ ÇÏ´Â ¹æ½ÄÀÌ´Ù. pipe, À¯´Ð½º µµ¸ÞÀÎ ¼ÒÄÏ, ¼¼¸¶Æ÷¾î, mutex, ¸Þ½ÃÁöÅ¥¸¦ ÀÌ¿ëÇÏ´Â ¹æ¹ýµéÀ» »ý°¢ÇØ º¼ ¼ö ÀÖÀ» °ÍÀÌ´Ù.

À̺¥Æ®°¡ ¹ß»ýµÉ ¶§ ½ÇÇàÇÒ callback(Äݹé)ÇÔ¼ö¸¦ µî·ÏÇÏ´Â ¹æ¹ýµµ ÀÖÀ» ¼ö ÀÖ°ÚÀ¸³ª °è¼ÓÀûÀÎ ÇÔ¼öÈ£Ãâ¿¡ ´ëÇÑ ºÎ´ã°¨À¸·Î (°³ÀÎÀûÀ¸·Î)¼±È£ÇÏÁö´Â ¾Ê°í ÀÖ´Ù.

¿¹Á¦

C++

wikipedia ¿¹Á¦

#include <list> 
#include <vector> 
#include <algorithm> 
#include <iostream> 
using namespace std; 
  
// The Abstract Observer 
class ObserverBoardInterface 
{ 
public: 
    virtual void update(float a,float b,float c) = 0; 
}; 
  
// Abstract Interface for Displays 
class DisplayBoardInterface 
{ 
public: 
    virtual void show() = 0; 
}; 
  
// The Abstract Subject 
class WeatherDataInterface 
{ 
public: 
    virtual void registerOb(ObserverBoardInterface* ob) = 0; 
    virtual void removeOb(ObserverBoardInterface* ob) = 0; 
    virtual void notifyOb() = 0; 
}; 
  
// The Concrete Subject 
class ParaWeatherData: public WeatherDataInterface 
{ 
public: 
    void SensorDataChange(float a,float b,float c) 
    { 
        m_humidity = a; 
        m_temperature = b; 
        m_pressure = c; 
        notifyOb(); 
    } 
  
    void registerOb(ObserverBoardInterface* ob) 
    { 
        m_obs.push_back(ob); 
    } 
  
    void removeOb(ObserverBoardInterface* ob) 
    { 
        m_obs.remove(ob); 
    } 
protected: 
    void notifyOb() 
    { 
        list<ObserverBoardInterface*>::iterator pos = m_obs.begin(); 
        while (pos != m_obs.end()) 
        { 
            ((ObserverBoardInterface* )(*pos))->update(m_humidity,m_temperature,m_pressure); 
            (dynamic_cast<DisplayBoardInterface*>(*pos))->show(); 
            ++pos; 
        } 
    } 
  
private: 
    float        m_humidity; 
    float        m_temperature; 
    float        m_pressure; 
    list<ObserverBoardInterface* > m_obs; 
}; 
  
// A Concrete Observer 
class CurrentConditionBoard : public ObserverBoardInterface, public DisplayBoardInterface 
{ 
public: 
    CurrentConditionBoard(ParaWeatherData& a):m_data(a) 
    { 
        m_data.registerOb(this); 
    } 
    void show() 
    { 
        cout<<"_____CurrentConditionBoard_____"<<endl; 
        cout<<"humidity: "<<m_h<<endl; 
        cout<<"temperature: "<<m_t<<endl; 
        cout<<"pressure: "<<m_p<<endl; 
        cout<<"_______________________________"<<endl; 
    } 
  
    void update(float h, float t, float p) 
    { 
        m_h = h; 
        m_t = t; 
        m_p = p; 
    } 
  
private: 
    float m_h; 
    float m_t; 
    float m_p; 
    ParaWeatherData& m_data; 
}; 
  
// A Concrete Observer 
class StatisticBoard : public ObserverBoardInterface, public DisplayBoardInterface 
{ 
public: 
    StatisticBoard(ParaWeatherData& a):m_maxt(-1000),m_mint(1000),m_avet(0),m_count(0),m_data(a) 
    { 
        m_data.registerOb(this); 
    } 
  
    void show() 
    { 
        cout<<"________StatisticBoard_________"<<endl; 
        cout<<"lowest  temperature: "<<m_mint<<endl; 
        cout<<"highest temperature: "<<m_maxt<<endl; 
        cout<<"average temperature: "<<m_avet<<endl; 
        cout<<"_______________________________"<<endl; 
    } 
  
    void update(float h, float t, float p) 
    { 
        ++m_count; 
        if (t>m_maxt) 
        { 
            m_maxt = t; 
        } 
        if (t<m_mint) 
        { 
            m_mint = t; 
        } 
        m_avet = (m_avet * (m_count-1) + t)/m_count; 
    } 
  
private: 
    float m_maxt; 
    float  m_mint; 
    float m_avet; 
    int m_count; 
    ParaWeatherData& m_data; 
}; 
  
int main(int argc, char *argv[]) 
{ 
  
    ParaWeatherData * wdata = new ParaWeatherData; 
    CurrentConditionBoard* currentB = new CurrentConditionBoard(*wdata); 
    StatisticBoard* statisticB = new StatisticBoard(*wdata); 
  
    wdata->SensorDataChange(10.2, 28.2, 1001); 
    wdata->SensorDataChange(12, 30.12, 1003); 
    wdata->SensorDataChange(10.2, 26, 806); 
    wdata->SensorDataChange(10.3, 35.9, 900); 
  
    wdata->removeOb(currentB); 
  
    wdata->SensorDataChange(100, 40, 1900);   
  
    delete statisticB; 
    delete currentB; 
    delete wdata; 
  
    return 0; 
} 
 

joinc ¿¹Á¦ : À¥·Î±× ·Î±×ºÐ¼®±â

°³ÀÎÀûÀ¸·Î RRD¸¦ ÀÌ¿ëÇÑ À¥·Î±× ºÐ¼® ½Ã½ºÅÛÀ» ±¸ÃàÇØ¼­ »ç¿ëÇϰí ÀÖ´Ù. ÀÌ ¹®¼­ÀÇ ÇÏ´Ü¿¡ º¸ÀÌ´Â ½Ã°£/Àϰ£º° ¹æ¹®Åë°è°¡ ÀÌ ½Ã½ºÅÛÀ» ÀÌ¿ëÇØ¼­ ¸¸µé¾î Á³´Ù. ÀÌ ½Ã½ºÅÛÀ» À§ÇÑ ÇÁ·Î±×·¥À» ¿¹·Î ÇØ¼­ obsever pattern¿¡ ´ëÇØ¼­ ¾Ë¾Æº¸±â·Î ÇϰڴÙ.

·Î±×ºÐ¼® ÇÁ·Î±×·¥¿¡ observer ÆÐÅÏÀ» »ç¿ëÇÑ ÀÌÀ¯´Â ·Î±×¸¦ ÇϳªÀÇ À̺¥Æ®·Î º¸°í À̸¦ °üÂûÇϰí ÀÖ´Ù°¡ À̺¥Æ®¸¦ ¹ß»ý½Ã۰í À̸¦ ó¸®ÇÏ´Â ¹æ½ÄÀ¸·Î ó¸®Çϱ⠿øÇ߱⠶§¹®ÀÌ´Ù.

ÀÌ ÇÁ·Î±×·¥Àº pageº°·Î 1½Ã°£µ¿¾È count¸¦ ÇÏ°í ±× °á°ú °ªÀ» RRDDB¿¡ ÀúÀåÇÏ´Â ÀÏÀ» ÇÑ´Ù. pageº° Ä«¿îÆ®¸¦ À§Çؼ­ STLÀÇ map ÄÁÅ×À̳ʸ¦ ÀÌ¿ëÇß´Ù. key´Â page À̸§ÀÌ µÇ°í value´Â intÇüÀÇ count°¡ µÇµµ·Ï Çß´Ù. ¾Æ·¡ÀÇ ÄÚµå´Â ¿ÏÀüÇÑ Äڵ尡 ¾Æ´Ñ »À´ëÄÚµå´Ù.
  1. ·Î±×¸¦ message·Î º»´Ù. observer Ŭ·¡½º´Â addMsg ¸Þ¼­µå¸¦ ±¸ÇöÇÑ´Ù.
  2. ·Î±×ºÐ¼® ¾Ë°í¸®Áò¿¡ µû¶ó¼­ ´Ù¾çÇÑ observer ±¸ÇöÀ» ¸¸µé°Ô µÉ °ÍÀÌ´Ù.
  3. Áï ·Î±×°¡ chain ruleÀ» Åë°úÇϸ鼭 ºÐ¼®µÈ´Ù.
  4. ÀÏÁ¤½Ã°£ÀÌ µÇ¸é, Subject Ŭ·¡½º´Â observer Ŭ·¡½ºÀÇ updateDB ¸Þ¼­µå¸¦ ½ÇÇà½ÃŲ´Ù.
  5. access log¿¡ »õ·Î¿î ¸Þ½ÃÁöÀÇ Ãß°¡¸¦ °üÂûÇÏ´Â °ÍÀº tail±¸ÇöÀ» ÀÌ¿ëÇÑ´Ù.

#include <map> 
#include <string> 
#include <list> 
using namespace std; 
 
// Abstract Observer 
class ObserverLogInterface 
{ 
    public: 
        virtual void addMsg(char *msg) = 0; 
        virtual int updateDB();  
        virtual void setTerm(int) = 0; 
        virtual int getTerm(int) = 0; 
}; 
/* 
 * Observer ±¸Çö 
 * ÀÌ ±¸ÇöÀº pageview¸¦ À§ÇÑ ¾Ë°í¸®ÁòÀ» Æ÷ÇÔÇÑ´Ù. 
 */ 
class PageView : public ObserverLogInterface 
{ 
    map<string pagename, int count> pageCount;  
    map<string pagename, int count>::iterator pos; 
    int term; 
    int alarmTime; 
    public: 
        void addMsg(char *msg) 
        { 
            string pagename; 
            // µé¾î¿Â ·Î±×¸Þ½ÃÁö¸¦ ÆÄ½ÌÇØ¼­ ÆäÀÌÁö À̸§À» ¾ò¾î¿Í¼­ counting ÇÑ´Ù.  
            // ÆÄ½ÌÇß´Ù°í °¡Á¤Ç졒         
            pos = pageCount.find(pagename); 
            if(pos == pageCount.end()) 
            { 
                pageCount[pagename] = 0; 
            } 
            else 
            { 
                pos->second++; 
            } 
        } 
 
        int updateDB() 
        { 
            // {pagename, count}¸¦ RRD¿¡ ÀúÀåÇÑ´Ù.     
            // RRD ÆÄÀÏÀÇ À̸§Àº paganeme.rrd·Î ÇϰڴÙ. 
            // ±×³É ±¸ÇöÇß´Ù°í °¡Á¤ 
            cout << "update RRD" <<endl; 
        } 
 
        void setTerm(int aterm) 
        { 
            // updateµÉ ½Ã°£À» ¼³Á¤ÇÑ´Ù. 
            // ÇöÀç ½Ã°£¿¡ + atermÀ» ÇÑ´Ù. 
            term = aterm; 
            alarmTime = term+time(NULL); 
        } 
 
        int getTerm() 
        { 
            return term; 
        } 
 
        int countDown() 
        { 
            // update ³²Àº ½Ã°£À» °è»êÇÑ´Ù. 
            // °ªÀÌ 0º¸´Ù ÀÛ´Ù¸é subject´Â updateDB¸¦ ¼öÇàÇÏ°Ô µÈ´Ù.  
            return alarmTime - time(NULL);  
        } 
};  
 
/* 
 * Observer ±¸Çö 
 * ÀÌ ±¸ÇöÀº À¯Àú °Ë»ö¾î count¸¦ À§ÇÑ ¾Ë°í¸®ÁòÀ» Æ÷ÇÔÇÑ´Ù.  
 * Å×½ºÆ®¸¦ À§ÇÑ Dummy ObserverÀÌ´Ù. 
 */ 
class KeywordCount : public ObserverLogInterface 
{ 
    public: 
        void addMsg(char *msg) 
        { 
        } 
 
        int updateDB() 
        { 
        } 
 
        void setTerm(int aterm) 
        { 
            term = aterm; 
            alarmTime = term+time(NULL); 
        } 
 
        int getTerm() 
        { 
            return term; 
        } 
 
        int countDown() 
        { 
            return alarmTime - time(NULL);  
        } 
};  
 
// The Abstract Subject 
class LogAnalyInterface 
{ 
    public: 
        virtual void registerOb(ObserverLogInterface *ob)=0; 
        virtual void removeOb(ObserverLogInterface *ob)=0; 
        virtual void notifyOb() = 0; 
}; 
 
/* 
  Subject ClassÀÇ ±¸Çö 
 */ 
class LogAnaly : public LoganalyInterface 
{ 
    private: 
        list<ObserverLogInterface *ob> m_obs; 
 
    public: 
        void registerOb(ObserverLogInterface *ob) 
        { 
            m_obs.push_back(ob); 
        } 
        void removeOb(ObserverLogInterface *ob) 
        { 
            m_obs.remove(ob); 
        } 
 
        // »õ·Î¿î ·Î±×¸Þ½ÃÁö°¡ µé¾î¿ÔÀ» ¶§. 
        void addMsg(char *msg) 
        { 
            notifyMsgOb(char *msg); 
        } 
 
        // update TimeÀ» È®ÀÎ 
        void checkUpdate() 
        { 
            notifyDbOb(char *msg); 
        } 
 
    protected: 
        void notifyMsgOb(char *msg) 
        { 
            list<ObserverLogInterface *ob>::iterator pos=m_obs.begin(); 
            while(pos != m_obs.end()) 
            { 
        ((ObserverLogInterface* )(*pos))->addMsg(msg); 
                pos++; 
            } 
        } 
        void notifyDbOb() 
        { 
            int term; 
            list<ObserverLogInterface *ob>::iterator pos=m_obs.begin(); 
            while(pos != m_obs.end()) 
            { 
                // ¸¸¾à update½Ã°£ÀÌ µÇ¾ú´Ù¸é updateDB ¸Þ¼­µå¸¦ ½ÇÇà½ÃŲ´Ù. 
                if( ((ObserverLogInterface* )(*pos))->countDown() < 0) 
                { 
                    term = (ObserverLogInterface* )(*pos))->getTerm(); 
                    (ObserverLogInterface* )(*pos))->updateDB(); 
                    // alarm TimeÀ» reset ÇÑ´Ù. 
                    (ObserverLogInterface* )(*pos))->setTerm(term); 
                } 
                pos++; 
            } 
        } 
}; 
 
int main() 
{ 
    AccessLogAnaly = new LogAnlay;  
    AccessLogAnaly->registerOb(new PageView); 
    AccessLogAnaly->registerOb(new KeywordCount); 
    while(tail(logfile)) 
    { 
        // tailÇÔ¼ö¸¦ ÀÌ¿ëÇØ¼­ »õ·Î¿î ·Î±×°¡ µé¾î¿À¸é   
        // PageView¿Í keywordCount Observer¿¡ ¸Þ½ÃÁö¸¦ ³Ñ±ä´Ù. 
        AccessLogAnaly->addMsg(); 
 
        // Update ½Ã°£À» üũÇÑ´Ù. 
        AccessLogAnaly->checkUpdate(); 
        sleep(1); 
    } 
} 
 

joinc ¿¹Á¦ : MVC ¸ðµ¨

°³ÀÎÀûÀ¸·Î ÁøÇàÁßÀÎ °£´Ü php ÇÁ·¹ÀÓ¿öÅ©ÀÎ dmfÀÇ MVC ¸ðµ¨À» ¿¹·Î ¼³¸íÇÑ´Ù. ÇÁ·¹ÀÓ¿öÅ©ÀÇ °³·«ÀûÀÎ ³»¿ëÀº dmf¹®¼­¸¦ Âü°íÇÏÀÚ. ÇÙ½ÉÀ» ¿ä¾àÇÏÀÚ¸é
  1. model subjectÀÇ ¿ªÇÒÀ» Çϰí
  2. view°¡ ObserverÀÇ ¿ªÇÒÀ» ÇÑ´Ù.
ÀÌ´Ù.

°Ë»ö¼­ºñ½º¸¦ À§ÇÑ model°ú view¸¦ °³¹ßÇÑ´Ù°í °¡Á¤À» ÇØº¸ÀÚ. ¸¸¾à °Ë»ö¼­ºñ½º°¡ Æ÷ÅÐÇüÀ̶ó¸é ùÆäÀÌÁöÀÇ °Ë»ö°á°ú view¿¡¼­ ´õº¸±â¸¦ Ŭ¸¯Çϸé Àü¹®°Ë»ö °á°ú view·Î ³Ñ¾î°¡°Ô µÉ °ÍÀ̹ǷΠÇϳªÀÇ modelÀÌ µÎ°³ÀÇ view¸¦ Á¦¾îÇØ¾ßÇÏ´Â °æ¿ì°¡ ¹ß»ýÇÑ´Ù. ÀÌ ¹®Á¦ÀÇ ÇØ°áÀ» À§Çؼ­ ¿ÉÀú¹ö¸ðµ¨À» Àû¿ëÇß´Ù. ¼¼·ÃµÈ ¸ð½ÀÀº ¾Æ´ÏÁö¸¸ ±×·°Àú·° °³³äÀûÀ¸·Î´Â ±¸ÇöµÇ¾î ÀÖ´Ù.
class MyModule extends Module 
{ 
    function model() 
    { 
        $domain = $this->options['d']; // ùÆäÀÌÁö °Ë»öÀÎÁö Àü¹®°Ë»öÀÎÁö¿¡ ´ëÇÑ uri ÀÎÀÚ°ª 
        $this->registerView($this->viewFirstPage,'t'); 
        $this->registerView($this->viewSearchPage,'s'); 
 
        $this->runView($domain); 
    } 
 
    function viewFirstPage() 
    { 
        // ùÆäÀÌÁö ºä 
    } 
 
    function viewSearchPage() 
    { 
        // Àü¹®°Ë»ö ÆäÀÌÁö ºä  
    } 
} 
 
EmailÀ» ±âÀÔÇϸé, ´ñ±ÛÀÌ ¸ÞÀÏ·Î Àü´ÞµË´Ï´Ù.