设计模式-观察者模式

Observer

观察者模式定义一种订阅机制,可在被观察对象事件发生时通知多个 “观察” 该对象的其他对象

  • 适用于构建多个对象间的依赖关系
  • 关键词:松耦合(主题与观察者)、广播机制(一对多)、动态(添加/删除订阅)
  • 缺点:缺少优先级管理,多观察者间的依赖关系可能导致错误

CPP

基本结构

Member FullName Description
主题 Subject 被观察类或接口,定义添加、移除和通知观察者的操作
具体主题 Concrete Subject 维护主题状态并通知观察者
观察者 Observer 观察类或接口,定义接收到通知后需要执行的操作
具体观察者 Concrete Observer 维护观察者状态并实现接收通知后执行的操作

UML接口图

实现步骤

  1. 定义观察者
1
2
3
4
5
class Observer {
public:
virtual ~Observer() = default;
virtual void update(int state) = 0;
};
  1. 定义主题,包含添加、删除、通知观察者操作
1
2
3
4
5
6
7
class Subject {
public:
virtual void attach(Observer* observer) = 0; // Add observer
virtual void detach(Observer* observer) = 0; // Remove observer
virtual void notify() = 0; // Notify all observers
virtual ~Subject() = default;
};
  1. 定义具体主题
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
class ConcreteSubject : public Subject {
private:
int state_; // State variable
std::vector<Observer*> observers_; // Observer list

public:
ConcreteSubject(int initial_state) : state_(initial_state) {}

void attach(Observer* observer) override {
observers_.push_back(observer);
}

void detach(Observer* observer) override {
auto it = std::find(observers_.begin(), observers_.end(), observer);
if (it != observers_.end()) {
observers_.erase(it);
}
}

void notify() override {
for (Observer* observer : observers_) {
observer->update(state_);
}
}

void setState(int state) {
state_ = state;
notify(); // Notify observers when state changes
}

int getState() const {
return state_;
}
};
  1. 定义具体对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class ConcreteObserver : public Observer {
private:
std::string name_;
int state_;
ConcreteSubject* subject_;

public:
ConcreteObserver(const std::string& name, ConcreteSubject* subject)
: name_(name), subject_(subject) {
subject_->attach(this); // Automatically attach to subject
}

void update(int state) override {
state_ = state;
std::cout << "Observer " << name_ << " received state: " << state_ << std::endl;
}

int getState() const {
return state_;
}
};

  1. 创建对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Create a subject
ConcreteSubject subject(10);

// Create observers
ConcreteObserver observer1("A", &subject);
ConcreteObserver observer2("B", &subject);
ConcreteObserver observer3("C", &subject);

// Change subject state and notify observers
subject.setState(20);

// Remove an observer and change state again
subject.detach(&observer2);
subject.setState(30);

Fortran

模式涉及观察者列表的添加与删除,需要通过链表或者变化数组大小实现

  • 此处通过定义观察者特征变量 name 简化过程
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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
module ObserverInterfaces
implicit none
private

! 定义观察者接口
type, abstract, public :: IObserver
contains
procedure(IUpdate), deferred :: update ! 更新方法
end type IObserver

abstract interface
subroutine IUpdate(this, state)
import IObserver
class(IObserver), intent(inout) :: this
integer, intent(in) :: state
end subroutine IUpdate
end interface

! 定义主题接口
type, abstract, public :: ISubject
contains
procedure(IAttach), deferred :: attach ! 添加观察者
procedure(IDetach), deferred :: detach ! 移除观察者
procedure(INotify), deferred :: notify ! 通知观察者
end type ISubject

abstract interface
subroutine IAttach(this, observer)
import ISubject
import IObserver
class(ISubject), intent(inout) :: this
integer, intent(in) :: observer
end subroutine IAttach

subroutine IDetach(this, observer)
import ISubject
import IObserver
class(ISubject), intent(inout) :: this
integer, intent(in) :: observer
end subroutine IDetach

subroutine INotify(this)
import ISubject
class(ISubject), intent(inout) :: this
end subroutine INotify
end interface

end module ObserverInterfaces

module ConcreteSubject
use ObserverInterfaces
implicit none
private

type, extends(ISubject), public :: ConcreteSubjectType
private
integer :: state_ = 0
integer, allocatable :: observers(:)
contains
procedure :: attach => AttachObserver
procedure :: detach => DetachObserver
procedure :: notify => NotifyObservers
procedure :: setState => SetState
procedure :: getState => GetState
end type ConcreteSubjectType

contains

subroutine AttachObserver(this, observer)
class(ConcreteSubjectType), intent(inout) :: this
integer, intent(in) :: observer
integer, allocatable :: new_observers(:)

if (.not. allocated(this%observers)) then
allocate(this%observers(1))
this%observers(1) = observer
return
end if
allocate(new_observers(size(this%observers) + 1))
new_observers(1:size(this%observers)) = this%observers
new_observers(size(this%observers) + 1) = observer
deallocate(this%observers)
this%observers = new_observers
deallocate(new_observers)
end subroutine AttachObserver

subroutine DetachObserver(this, observer)
class(ConcreteSubjectType), intent(inout) :: this
integer, intent(in) :: observer
integer :: i, obs_size
logical :: found
integer, allocatable :: new_observers(:)

obs_size = size(this%observers)
allocate(new_observers(obs_size - 1))
found = .false.
do i = 1, obs_size
if (this%observers(i) == observer) then
found = .true.
else
if (i < obs_size) then
new_observers(i) = this%observers(i)
else
new_observers(i-1) = this%observers(i)
end if
end if
end do
if (found) then
this%observers = new_observers
deallocate(new_observers)
end if
end subroutine DetachObserver

subroutine NotifyObservers(this)
class(ConcreteSubjectType), intent(inout) :: this
integer :: i

do i = 1, size(this%observers)
write(*,*) "Notifying Observer ", this%observers(i), " with state: ", this%state_
end do
end subroutine NotifyObservers

subroutine SetState(this, state)
class(ConcreteSubjectType), intent(inout) :: this
integer, intent(in) :: state
this%state_ = state
call this%notify()
end subroutine SetState

function GetState(this) result(state)
class(ConcreteSubjectType), intent(in) :: this
integer :: state
state = this%state_
end function GetState

end module ConcreteSubject

module ConcreteObservers
use ObserverInterfaces
implicit none
private

type, extends(IObserver), public :: ConcreteObserverType
private
integer, public :: name = 0
integer :: state_ = -1
integer :: subject_id_ = -1
contains
procedure :: update => UpdateState
end type ConcreteObserverType

contains

subroutine UpdateState(this, state)
class(ConcreteObserverType), intent(inout) :: this
integer, intent(in) :: state
this%state_ = state
write(*,*) "Observer ", this%name, " received state: ", this%state_
end subroutine UpdateState

end module ConcreteObservers

program ObserverPattern
use ObserverInterfaces
use ConcreteSubject
use ConcreteObservers
implicit none

type(ConcreteSubjectType) :: subject
type(ConcreteObserverType), pointer :: observer1, observer2, observer3

allocate(observer1)
observer1%name = 1

allocate(observer2)
observer2%name = 2

allocate(observer3)
observer3%name = 3

call subject%attach(observer1%name)
call subject%attach(observer2%name)
call subject%attach(observer3%name)

write(*,*) "Changing subject state to 20..."
call subject%setState(20)

write(*,*) ""
write(*,*) "Removing observer 2..."
call subject%detach(observer2%name)

write(*,*) "Changing subject state to 30..."
call subject%setState(30)

deallocate(observer1, observer2, observer3)

end program ObserverPattern

Reference

refactoringguru | 观察者模式
wx_幼儿园的学霸 | C++设计模式——观察者模式
腾讯云 | 【C++11】 改进我们的设计模式—观察者模式

0%