Skip to content

Commit f5cc5c6

Browse files
xiao chengxiao cheng
xiao cheng
authored and
xiao cheng
committed
observer pattern
1 parent 32ec1ef commit f5cc5c6

File tree

6 files changed

+418
-0
lines changed

6 files changed

+418
-0
lines changed

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,5 @@ if(Boost_FOUND)
3232
add_subdirectory(Interpreter)
3333
add_subdirectory(IteratorPattern)
3434
add_subdirectory(Visitor)
35+
add_subdirectory(Observer)
3536
endif()

Observer/CMakeLists.txt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
cmake_minimum_required(VERSION 3.8)
2+
3+
project(Observer)
4+
5+
include_directories(${Boost_INCLUDE_DIRS})
6+
7+
add_executable(Observer_example1 example1.cpp)
8+
target_link_libraries(Observer_example1 PUBLIC gtest_main ${Boost_LIBRARIES})
9+
install(TARGETS Observer_example1 RUNTIME DESTINATION ../bin)
10+
11+
add_executable(Observer_example2 example2.cpp)
12+
target_link_libraries(Observer_example2 PUBLIC gtest_main ${Boost_LIBRARIES})
13+
install(TARGETS Observer_example2 RUNTIME DESTINATION ../bin)
14+
15+
16+
17+
18+
19+
add_executable(Observer_test observer_test.cpp)
20+
target_link_libraries(Observer_test PUBLIC gtest_main ${Boost_LIBRARIES})
21+
install(TARGETS Observer_test RUNTIME DESTINATION ../bin)

Observer/example1.cpp

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
#include <iostream>
2+
#include <vector>
3+
4+
using namespace std;
5+
6+
class Observer
7+
{
8+
public:
9+
virtual void update(int value) = 0;
10+
};
11+
12+
class Subject
13+
{
14+
int m_value;
15+
vector<Observer*> m_views;
16+
17+
public:
18+
void attach(Observer *obs)
19+
{
20+
m_views.push_back(obs);
21+
}
22+
void set_val(int value)
23+
{
24+
m_value = value;
25+
notify();
26+
}
27+
void notify()
28+
{
29+
for (int i = 0; i < m_views.size(); ++i)
30+
m_views[i]->update(m_value);
31+
}
32+
};
33+
34+
class DivObserver : public Observer
35+
{
36+
int m_div;
37+
38+
public:
39+
DivObserver(Subject *model, int div)
40+
{
41+
model->attach(this);
42+
m_div = div;
43+
}
44+
/* virtual */ void update(int v)
45+
{
46+
cout << v << " div " << m_div << " is " << v / m_div << '\n';
47+
}
48+
};
49+
50+
class ModObserver : public Observer
51+
{
52+
int m_mod;
53+
54+
public:
55+
ModObserver(Subject *model, int mod)
56+
{
57+
model->attach(this);
58+
m_mod = mod;
59+
}
60+
/* virtual */ void update(int v)
61+
{
62+
cout << v << " mod " << m_mod << " is " << v % m_mod << '\n';
63+
}
64+
};
65+
66+
int main()
67+
{
68+
Subject subj;
69+
DivObserver divObs1(&subj, 4);
70+
DivObserver divObs2(&subj, 3);
71+
ModObserver modObs3(&subj, 3);
72+
subj.set_val(14);
73+
}

Observer/example2.cpp

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
#include <iostream>
2+
#include <vector>
3+
using namespace std;
4+
5+
// independent subject, only coupled with base class: Observer
6+
class Subject
7+
{
8+
vector<class Observer *> views;
9+
int value;
10+
11+
public:
12+
void attach(Observer *obs)
13+
{
14+
views.push_back(obs);
15+
}
16+
void setVal(int val)
17+
{
18+
value = val;
19+
notify();
20+
}
21+
int getVal()
22+
{
23+
return value;
24+
}
25+
void notify();
26+
};
27+
28+
class Observer
29+
{
30+
//dependent functionality
31+
Subject *model;
32+
int denom;
33+
34+
public:
35+
Observer(Subject *mod, int div)
36+
{
37+
model = mod;
38+
denom = div;
39+
//Observers register themselves with the Subject
40+
model->attach(this);
41+
}
42+
virtual void update() = 0;
43+
44+
protected:
45+
Subject *getSubject()
46+
{
47+
return model;
48+
}
49+
int getDivisor()
50+
{
51+
return denom;
52+
}
53+
};
54+
55+
void Subject::notify()
56+
{
57+
//broadcasts
58+
for (int i = 0; i < views.size(); i++)
59+
views[i]->update();
60+
}
61+
62+
// View
63+
class DivObserver : public Observer
64+
{
65+
public:
66+
DivObserver(Subject *mod, int div) : Observer(mod, div) {}
67+
void update()
68+
{
69+
// 6. "Pull" information of interest
70+
int v = getSubject()->getVal(), d = getDivisor();
71+
cout << v << " div " << d << " is " << v / d << '\n';
72+
}
73+
};
74+
75+
class ModObserver : public Observer
76+
{
77+
public:
78+
ModObserver(Subject *mod, int div) : Observer(mod, div) {}
79+
void update()
80+
{
81+
int v = getSubject()->getVal(), d = getDivisor();
82+
cout << v << " mod " << d << " is " << v % d << '\n';
83+
}
84+
};
85+
86+
int main()
87+
{
88+
Subject subj;
89+
DivObserver divObs1(&subj, 4); // 7. Client configures the number and
90+
DivObserver divObs2(&subj, 3); // type of Observers
91+
ModObserver modObs3(&subj, 3);
92+
subj.setVal(14);
93+
}

Observer/example3.cpp

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
#include <string>
2+
#include <vector>
3+
#include <iostream>
4+
5+
6+
7+
using namespace std;
8+
9+
10+
#include <boost/any.hpp>
11+
using namespace boost;
12+
13+
namespace
14+
{
15+
16+
struct Person; // subject
17+
18+
struct PersonListener // base observer
19+
{
20+
virtual ~PersonListener() = default;
21+
22+
virtual void person_changed(Person &p, const string &property_name, const any new_value) = 0;
23+
};
24+
25+
struct Person
26+
{
27+
explicit Person(int age)
28+
29+
: age(age)
30+
{
31+
}
32+
33+
int get_age() const
34+
{
35+
return age;
36+
}
37+
38+
void set_age(const int age);
39+
40+
bool get_can_vote() const
41+
{
42+
return age >= 16;
43+
}
44+
45+
void subscribe(PersonListener *pl);
46+
47+
void notify(const string &property_name, const any new_value);
48+
49+
private:
50+
int age;
51+
vector<PersonListener *> listeners;
52+
};
53+
54+
void Person::set_age(const int age)
55+
{
56+
if (this->age == age)
57+
return;
58+
59+
auto old_c_v = get_can_vote();
60+
61+
this->age = age;
62+
notify("age", this->age);
63+
64+
auto new_c_v = get_can_vote();
65+
if (old_c_v != new_c_v)
66+
{
67+
notify("can_vote", new_c_v);
68+
}
69+
}
70+
71+
void Person::subscribe(PersonListener *pl)
72+
{
73+
listeners.push_back(pl);
74+
}
75+
76+
void Person::notify(const string &property_name, const any new_value)
77+
{
78+
for (const auto listener : listeners)
79+
listener->person_changed(*this, property_name, new_value);
80+
}
81+
82+
struct ConsoleListener : PersonListener
83+
{
84+
void person_changed(Person &p, const string &property_name, const any new_value) override
85+
{
86+
cout << "person's " << property_name << " has been changed to ";
87+
if (property_name == "age")
88+
{
89+
cout << any_cast<int>(new_value);
90+
}
91+
else if (property_name == "can_vote")
92+
{
93+
cout << any_cast<bool>(new_value);
94+
}
95+
cout << "\n";
96+
}
97+
};
98+
99+
int main()
100+
{
101+
Person p{14};
102+
ConsoleListener cl;
103+
p.subscribe(&cl);
104+
p.set_age(15);
105+
p.set_age(16);
106+
107+
getchar();
108+
return 0;
109+
}
110+
111+
} // namespace

0 commit comments

Comments
 (0)