观察者模式是一种行为设计模式,它使你能够定义一个订阅机制,可以在对象事件发生时通知多个“观察”该对象的其他对象。
模式的动机
观察者模式可以用来实现事件处理系统,如GUI事件。在这种情况下,我们可以将用户代码视为观察者,GUI事件管理器作为被观察者。事件管理器保存了一个列表,指向所有需要通知的对象,并且在状态改变时遍历它们。
模式的结构
观察者模式包括以下角色:
- Subject(主题):知道它的观察者。可以有任意多个观察者观察同一个主题。
- ConcreteSubject(具体主题):将有关状态存入具体观察者对象,在具体主题内部状态改变时,给所有登记过的观察者发出通知。
- Observer(观察者):为那些在主题发生改变时需获得通知的对象定义一个更新接口。
- ConcreteObserver(具体观察者):维护一个指向具体主题对象的引用。存储有关状态,这些状态应与主题的状态保持一致。实现 Observer 的更新接口以使自身状态与主题的状态保持一致。
Ruby 实现
在Ruby中,我们可以通过使用模块和类来实现观察者模式。
定义主题类
// www.javascriptcn.com code example
class Subject
include Enumerable
def initialize
@observers = []
end
def add_observer(observer)
@observers << observer
end
def delete_observer(observer)
@observers.delete(observer)
end
def notify_observers
@observers.each { |observer| observer.update(self) }
end
def each(&block)
@observers.each(&block)
end
end定义观察者类
class Observer
attr_accessor :subject
def update(subject)
raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
end
end具体主题和观察者
// www.javascriptcn.com code example
class ConcreteSubject < Subject
attr_accessor :state
def initialize
super
@state = 0
end
def change_state(new_state)
puts "主题状态从 #{@state} 改变为 #{new_state}"
@state = new_state
notify_observers
end
end
class ConcreteObserver < Observer
def initialize(name)
@name = name
end
def update(subject)
puts "#{@name} 收到通知: 主题状态更改为 #{subject.state}"
end
end使用观察者模式
// www.javascriptcn.com code example
subject = ConcreteSubject.new
observer1 = ConcreteObserver.new("观察者1")
observer2 = ConcreteObserver.new("观察者2")
subject.add_observer(observer1)
subject.add_observer(observer2)
subject.change_state(10)
subject.change_state(20)以上代码展示了如何在Ruby中实现观察者模式。在这个例子中,ConcreteSubject 类是被观察的对象,它包含了状态,并且有一个方法用于改变状态并通知所有的观察者。ConcreteObserver 类则是具体的观察者,它们实现了 update 方法来响应主题状态的变化。
通过这种方式,我们可以很容易地扩展或修改我们的系统,而无需更改现有的代码。只需要添加新的观察者或者删除旧的观察者即可。