프로그래밍 검색 블로그

옵저버 패턴 Observer Pattern [function] 본문

C++ 패턴

옵저버 패턴 Observer Pattern [function]

코딩조무사 2017. 10. 4. 02:01

이쪽은 std function을 활용

장점은 한 클래스에 같은 함수로 구분해서 사용가능 

단점은 callback을 선택해서 제거가 불가능하고 모든 callback을 제거해야함 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#include <vector>
#include <algorithm>
#include <functional>
#include <list>
#include <type_traits>
#include <future>
 
template<typename _ArgumentType>
class Observable{
    using _MyT = Observable<_ArgumentType>;
    using _MyObserverType = const std::function<void(const _MyT&, _ArgumentType)>;
    std::list<_MyObserverType> mObservers;
    
    using synchronized = std::lock_guard<std::mutex>;
    std::mutex mObserverMutex;
    
 
public:
    void addObservers(_MyObserverType& o){
        if(o){
            synchronized lock(mObserverMutex);
            mObservers.push_back(o);
        }
    }
    
    void deleteAllObservers(){
        mObservers.clear();
    }
    
    
    void notifyObservers(_ArgumentType&& arg){
        std::future<void> notifiyRes;
        
        {
            synchronized lock(mObserverMutex);
 
            
            /**
             * 여기서 호출하기에 적절한지 검사하고 모든 mObservers의 원소들을 복사하여 비동기로 호출한다.
             * 이때 새로 추가되거나 제거된 옵저버에 대해서는 신경쓰지 않는다.
             */
            if(mObservers.size() == 0){
                return;
            }
            
            try{
                notifiyRes = callObserverUpdateAsync(std::vector<_MyObserverType>(mObservers.begin(), mObservers.end()), std::move(arg));
            }catch(std::system_error&){}
            
        }
        
        if(notifiyRes.valid()){
            notifiyRes.get();
        }
    }
 
    inline void notifyObservers(){ notifyObservers(_ArgumentType()); }
    
private:
    
    /**
     * 한 옵저버에서 비동기 실행을 한다.
     * 실행 시에는 아래에 있는 callObserverUpdateAsync 로 실행한다.
     */
    auto callObserverUpdateAsync(_MyObserverType& observers,
                                 const _ArgumentType& arg) -> std::future<void>{
        return std::async(std::launch::async,[=]{
            try{
                observers(*this, arg);
            }catch(...){
                
            }
        });
    }
    
    /**
     * [(이 함수에서 mObservers에 들어있는 함수들을 std::async 호출을 통해서
     * 비동기로 실행한다.
     * 실행후 모든 Observer의 실행이 끝날때 같이 종료한다.)]
     * - 위에 설명된 동작을 하는 비동기 작업을 반환한다.
     */
    auto callObserverUpdateAsync(std::vector<_MyObserverType> observers, _ArgumentType&& arg) -> std::future<void>{
        return std::async(std::launch::async,[=]{
            std::vector<std::future<void>> callResults;
            
            for(auto& f : observers){
                try{
                    callResults.push_back(callObserverUpdateAsync(f, arg));
                }catch(std::system_error&){}
            }
            
            for(auto& r : callResults){
                if (r.valid()) {
                    r.get();
                }
            }
        });
    }
};
cs





테스트 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <iostream>
using test_type = void*;
std::mutex printLock;
 
using namespace std;
class ObserverImpl3 {
public:
    void OnUpdate(const Observable<test_type>& m, test_type value){
        std::lock_guard<std::mutex> lock(printLock);
        cout <<"ObserverImpl3 val:" << value <<endl;
    }
    void OnUpdate2(const Observable<test_type>& m, test_type value){
        std::lock_guard<std::mutex> lock(printLock);
        cout <<"ObserverImpl4 val:" << value <<endl;
    }
};
 
#define BIND_METHOD2(_INSTANCE_, _METHOD_) (std::bind(&decltype(_INSTANCE_)::_METHOD_, _INSTANCE_, std::placeholders::_1, std::placeholders::_2))
 
int main(int argc, const char * argv[]) {
    
    Observable<test_type> o;
    ObserverImpl3 listener;
    o.addObservers(BIND_METHOD2(listener, OnUpdate2));
    o.addObservers(BIND_METHOD2(listener, OnUpdate));
    o.notifyObservers(nullptr);
    
    o.deleteAllObservers();
}
 
 
cs


'C++ 패턴' 카테고리의 다른 글

C++ 예외 처리  (0) 2017.10.18
옵저버 패턴 Observer Pattern [Class 구조]  (0) 2017.10.03
Comments