简介
观察者模式(Observer Pattern)是一种行为型模式。它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
观察者模式使用三个类Subject、Observer和Client。Subject对象带有绑定观察者到Client对象和从Client对象解绑观察者的方法。我们创建Subject类、Observer抽象类和扩展了抽象类Observer的实体类。
作用
- 一个对象状态更新,其他依赖对象收到通知和自动更新的机制。
- 实现模块化分离,实现主题与观察者交互对象之间的松耦合。
1)观察者定义了对象之间一对多的关系。
2)被观察者(主题)用一个共同的接口来更新观察者。
3)观察者和被观察者用松耦合方式结合,被观察者不知道观察者的细节,只知道观察者实现了观察者接口。
实现步骤
- 创建观察者observer基础接口,包含主题和更新方法
- 创建主题subject抽象类,包含observer列表以及添加和删除方法
- 创建具体的主题类,实现通知方法,发布通知时轮询通知全部观察者
- 创建多个具体观察者,与主题关联,并实现自己的更新方法
- 客户调用时先声明主题,再将观察者分别添加到主题,当主题发布通知时,观察者自动更新
UML
Java代码
观察者接口
- // ObserverAPI.java 观察者接口,Java 9已经默认支持Observer接口
- // 这里避免冲突采取ObserverAPI命名
- public interface ObserverAPI {
- public Subject subject = null;
- public void update(String content);
- }
复制代码 具体观察者
- // ConcreteObserver.java 具体的观察者实现类,也可以看成订阅者,关联对应的主题类。
- // 不同的观察者也可以对应多个主题
- public class ConcreteObserver implements ObserverAPI {
- public Subject subject;
- // 给观察者绑定主题,同时把观察者添加到主题列表
- public ConcreteObserver(Subject subject) {
- this.subject = subject;
- this.subject.register((ObserverAPI) this);
- }
- // 观察者发出更新通知,不用单独告诉订阅者,由订阅者自行监听
- public void update(String content) {
- System.out.println(String.format("%s::update() [subject.name = %s content = %s]",
- this.getClass().getName(),
- this.subject.getName(), content));
- }
- }
复制代码- // ConcreteObserver2.java 具体的观察者实现类,也可以看成订阅者,关联对应的主题类。
- // 不同的观察者可以对应不同的主题。
- public class ConcreteObserver2 implements ObserverAPI {
- // 这里没有在构造器就绑定某个主题,而是从客户角度去注册观察者
- public ConcreteObserver2() {
- }
- // 观察者发出更新通知,观察者自行监听
- public void update(String content) {
- System.out.println(String.format("%s::update() [content = %s]",
- this.getClass().getName(), content));
- }
- }
复制代码 抽象主题类
- // Subject.java 定义抽象主题类或者接口,供具体主题类继承
- public abstract class Subject {
- private String name;
- // protected Set<ObserverAPI> observers = new HashSet<>();
- protected List<ObserverAPI> observers = new ArrayList<>();
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public void register(ObserverAPI observer) {
- System.out.println(this.getClass().getName() + "::register() [observer = " + observer.getClass().getSimpleName() + "]");
- observers.add(observer);
- }
- public void remove(ObserverAPI observer) {
- observers.remove(observer);
- }
- // 通知由具体类来实现逻辑
- public abstract void notify(String name);
- }
复制代码 具体主题类
- // ConcreteSubject.java 观察者主题类,也是发布者,重写具体的通知方法。不同主题可以关联不同的观察者。
- public class ConcreteSubject extends Subject {
- public ConcreteSubject(String name) {
- this.setName(name);
- }
- // 不同的主题类有自己的通知方法,批量通知绑定的观察者
- @Override
- public void notify(String content) {
- System.out.println(this.getClass().getName() + "::notify() [content = " + content + "]");
- for (Object observer : this.observers) {
- ((ObserverAPI) observer).update(content);
- }
- }
- }
复制代码 测试调用
- /**
- * 观察者模式应用非常广泛,主要是观察者提前绑定到发布者
- * 当发布者发布消息时,批量广播通知,而无需逐一通知
- * 观察者监听到消息后自己决定采取哪一种行为
- */
- // 定义一个主题,也就是发布者
- Subject concreteSubject = new ConcreteSubject("subject1");
- // 再声明观察者,通过构造器注册到主题上
- ObserverAPI observer1 = new ConcreteObserver(concreteSubject);
- // 也可以单独给主题注册一个新的观察者
- concreteSubject.register(new ConcreteObserver2());
- // 可以移除观察者对象,可以打开注释试下
- // concreteSubject.remove(observer1);
- // 主题开始发布新通知,各观察者自动更新
- concreteSubject.notify("hello, this is broadcast.");
复制代码 Python代码
观察者接口
- # ObserverAPI.py 观察者抽象父类,定义一些公共方法
- class ObserverAPI:
- def __init__(self, name):
- self.name = name
- # 观察者发出更新通知,观察者自行监听
- def update(self, content):
- print(self.__class__.__name__ + '::update() [content = ' + content + ']')
- def set_name(self, name):
- self.name = name
复制代码 具体观察者
- # ConcreteObserver.py 具体的观察者实现类,也可以看成订阅者,关联对应的主题类。
- # 不同的观察者也可以对应多个主题
- from src.ObserverAPI import ObserverAPI
- # 具体的观察者实现类,也可以看成订阅者,关联对应的主题类。
- # 不同的观察者也可以对应多个主题
- class ConcreteObserver(ObserverAPI):
- # 给观察者绑定主题,同时把观察者添加到主题列表
- def __init__(self, subject, name):
- ObserverAPI.__init__(self, name)
-
- # python3支持的父类调用
- # super(ConcreteObserver, self).__init__(name)
- # super().__init__(name)
- self.subject = subject
- subject.register(self)
- # 观察者发出更新通知,不用单独告诉订阅者,由订阅者自行监听
- def update(self, content):
- print(self.__class__.__name__ + '::update() [subject.name = ' +
- self.subject.name + ' content = ' + content + ']')
复制代码- # ConcreteObserver2.py 具体的观察者实现类,也可以看成订阅者,关联对应的主题类。
- # 不同的观察者可以对应不同的主题。
- from src.ObserverAPI import ObserverAPI
- # 具体的观察者实现类,也可以看成订阅者,关联对应的主题类。
- # 不同的观察者可以对应不同的主题。
- class ConcreteObserver2(ObserverAPI):
- # 这里没有在构造器就绑定某个主题,而是从客户角度去注册观察者
- # 观察者发出更新通知,观察者自行监听
- # def update(self, content):
- # print(self.__class__.__name__ + '::update() [content = ' + content +']')
-
- pass
复制代码 抽象主题类
- # Subject.py 定义抽象主题类或者接口,供具体主题类继承
- class Subject:
- def __init__(self, name):
- self.name = name
- self.observers = []
- def get_name(self):
- return self.name
- def set_name(self, name):
- self.name = name
- def register(self, observer):
- print(self.__class__.__name__ + '::register() [observer = ' +
- observer.__class__.__name__ + ']')
- self.observers.append(observer)
- def remove(self, observer):
- self.observers.remove(observer)
- # 通知由具体类来实现逻辑
- def notify(self, name):
- pass
复制代码 具体主题类
- // ConcreteSubject.py 观察者主题类,也是发布者,重写具体的通知方法。不同主题可以关联不同的观察者。
- from src.Subject import Subject
- # 观察者主题类,也是发布者,重写具体的通知方法。不同主题可以关联不同的观察者。
- class ConcreteSubject(Subject):
- # 不同的主题类有自己的通知方法,批量通知绑定的观察者
- def notify(self, content):
- print(self.__class__.__name__ + '::notify() [content = ' + content +
- ']')
- for observer in self.observers:
- observer.update(content)
复制代码 测试调用
- import sys
- import os
- os_path = os.getcwd()
- sys.path.append(os_path)
- from src.ConcreteSubject import ConcreteSubject
- from src.ConcreteObserver import ConcreteObserver
- from src.ConcreteObserver2 import ConcreteObserver2
- def test():
- '''
- * 观察者模式应用非常广泛,主要是观察者提前绑定到发布者
- * 当发布者发布消息时,批量广播通知,而无需逐一通知
- * 观察者监听到消息后自己决定采取哪一种行为
- '''
- # 定义一个主题,也就是发布者
- concrete_subject = ConcreteSubject('subject1')
- # 再声明观察者,通过构造器注册到主题上
- observer1 = ConcreteObserver(concrete_subject, 'observer1')
- # 也可以单独给主题注册一个新的观察者
- observer2 = ConcreteObserver2('observer2')
- concrete_subject.register(observer2)
- # 可以移除观察者对象
- # concrete_subject.remove(observer1)
- # 主题开始发布新通知,各观察者自动更新
- concrete_subject.notify('hello, this is broadcast.')
- if __name__ == '__main__':
- print(__file__)
- print("test start:")
- test()
复制代码 更多语言版本
不同语言实现设计模式:https://github.com/microwind/design-pattern
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |