找回密码
 立即注册
首页 业界区 业界 【观察者设计模式详解】C/Java/JS/Go/Python/TS不同语言 ...

【观察者设计模式详解】C/Java/JS/Go/Python/TS不同语言实现

请蒂 2025-6-6 09:42:41
简介

观察者模式(Observer Pattern)是一种行为型模式。它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
观察者模式使用三个类Subject、Observer和Client。Subject对象带有绑定观察者到Client对象和从Client对象解绑观察者的方法。我们创建Subject类、Observer抽象类和扩展了抽象类Observer的实体类。
作用


  • 一个对象状态更新,其他依赖对象收到通知和自动更新的机制。
  • 实现模块化分离,实现主题与观察者交互对象之间的松耦合。
    1)观察者定义了对象之间一对多的关系。
    2)被观察者(主题)用一个共同的接口来更新观察者。
    3)观察者和被观察者用松耦合方式结合,被观察者不知道观察者的细节,只知道观察者实现了观察者接口。
实现步骤


  • 创建观察者observer基础接口,包含主题和更新方法
  • 创建主题subject抽象类,包含observer列表以及添加和删除方法
  • 创建具体的主题类,实现通知方法,发布通知时轮询通知全部观察者
  • 创建多个具体观察者,与主题关联,并实现自己的更新方法
  • 客户调用时先声明主题,再将观察者分别添加到主题,当主题发布通知时,观察者自动更新
UML

 
1.png
 
Java代码

观察者接口
  1. // ObserverAPI.java 观察者接口,Java 9已经默认支持Observer接口
  2. // 这里避免冲突采取ObserverAPI命名
  3. public interface ObserverAPI {
  4.    public Subject subject = null;
  5.    public void update(String content);
  6. }
复制代码
具体观察者
  1. // ConcreteObserver.java 具体的观察者实现类,也可以看成订阅者,关联对应的主题类。
  2. // 不同的观察者也可以对应多个主题
  3. public class ConcreteObserver implements ObserverAPI {
  4.    public Subject subject;
  5.    // 给观察者绑定主题,同时把观察者添加到主题列表
  6.    public ConcreteObserver(Subject subject) {
  7.       this.subject = subject;
  8.       this.subject.register((ObserverAPI) this);
  9.    }
  10.    // 观察者发出更新通知,不用单独告诉订阅者,由订阅者自行监听
  11.    public void update(String content) {
  12.       System.out.println(String.format("%s::update() [subject.name = %s content = %s]",
  13.             this.getClass().getName(),
  14.             this.subject.getName(), content));
  15.    }
  16. }
复制代码
  1. // ConcreteObserver2.java 具体的观察者实现类,也可以看成订阅者,关联对应的主题类。
  2. // 不同的观察者可以对应不同的主题。
  3. public class ConcreteObserver2 implements ObserverAPI {
  4.   // 这里没有在构造器就绑定某个主题,而是从客户角度去注册观察者
  5.   public ConcreteObserver2() {
  6.   }
  7.   // 观察者发出更新通知,观察者自行监听
  8.   public void update(String content) {
  9.     System.out.println(String.format("%s::update() [content = %s]",
  10.         this.getClass().getName(), content));
  11.   }
  12. }
复制代码
抽象主题类
  1. // Subject.java 定义抽象主题类或者接口,供具体主题类继承
  2. public abstract class Subject {
  3.    private String name;
  4.    // protected Set<ObserverAPI> observers = new HashSet<>();
  5.    protected List<ObserverAPI> observers = new ArrayList<>();
  6.    public String getName() {
  7.       return name;
  8.    }
  9.    public void setName(String name) {
  10.       this.name = name;
  11.    }
  12.    public void register(ObserverAPI observer) {
  13.       System.out.println(this.getClass().getName() + "::register() [observer = " + observer.getClass().getSimpleName() + "]");
  14.       observers.add(observer);
  15.    }
  16.    public void remove(ObserverAPI observer) {
  17.       observers.remove(observer);
  18.    }
  19.    // 通知由具体类来实现逻辑
  20.    public abstract void notify(String name);
  21. }
复制代码
具体主题类
  1. // ConcreteSubject.java 观察者主题类,也是发布者,重写具体的通知方法。不同主题可以关联不同的观察者。
  2. public class ConcreteSubject extends Subject {
  3.    public ConcreteSubject(String name) {
  4.       this.setName(name);
  5.    }
  6.    // 不同的主题类有自己的通知方法,批量通知绑定的观察者
  7.    @Override
  8.    public void notify(String content) {
  9.       System.out.println(this.getClass().getName() + "::notify() [content = " + content + "]");
  10.       for (Object observer : this.observers) {
  11.          ((ObserverAPI) observer).update(content);
  12.       }
  13.    }
  14. }
复制代码
测试调用
  1.     /**
  2.      * 观察者模式应用非常广泛,主要是观察者提前绑定到发布者
  3.      * 当发布者发布消息时,批量广播通知,而无需逐一通知
  4.      * 观察者监听到消息后自己决定采取哪一种行为
  5.      */
  6.     // 定义一个主题,也就是发布者
  7.     Subject concreteSubject = new ConcreteSubject("subject1");
  8.     // 再声明观察者,通过构造器注册到主题上
  9.     ObserverAPI observer1 = new ConcreteObserver(concreteSubject);
  10.     // 也可以单独给主题注册一个新的观察者
  11.     concreteSubject.register(new ConcreteObserver2());
  12.     // 可以移除观察者对象,可以打开注释试下
  13.     // concreteSubject.remove(observer1);
  14.     // 主题开始发布新通知,各观察者自动更新
  15.     concreteSubject.notify("hello, this is broadcast.");
复制代码
Python代码

观察者接口
  1. # ObserverAPI.py 观察者抽象父类,定义一些公共方法
  2. class ObserverAPI:
  3.     def __init__(self, name):
  4.         self.name = name
  5.     # 观察者发出更新通知,观察者自行监听
  6.     def update(self, content):
  7.         print(self.__class__.__name__ + '::update() [content = ' + content + ']')
  8.     def set_name(self, name):
  9.         self.name = name
复制代码
具体观察者
  1. # ConcreteObserver.py 具体的观察者实现类,也可以看成订阅者,关联对应的主题类。
  2. # 不同的观察者也可以对应多个主题
  3. from src.ObserverAPI import ObserverAPI
  4. # 具体的观察者实现类,也可以看成订阅者,关联对应的主题类。
  5. # 不同的观察者也可以对应多个主题
  6. class ConcreteObserver(ObserverAPI):
  7.     # 给观察者绑定主题,同时把观察者添加到主题列表
  8.     def __init__(self, subject, name):
  9.         ObserverAPI.__init__(self, name)
  10.         
  11.         # python3支持的父类调用
  12.         # super(ConcreteObserver, self).__init__(name)
  13.         # super().__init__(name)
  14.         self.subject = subject
  15.         subject.register(self)
  16.     # 观察者发出更新通知,不用单独告诉订阅者,由订阅者自行监听
  17.     def update(self, content):
  18.         print(self.__class__.__name__ + '::update() [subject.name = ' +
  19.               self.subject.name + ' content = ' + content + ']')
复制代码
  1. # ConcreteObserver2.py 具体的观察者实现类,也可以看成订阅者,关联对应的主题类。
  2. # 不同的观察者可以对应不同的主题。
  3. from src.ObserverAPI import ObserverAPI
  4. # 具体的观察者实现类,也可以看成订阅者,关联对应的主题类。
  5. # 不同的观察者可以对应不同的主题。
  6. class ConcreteObserver2(ObserverAPI):
  7.     # 这里没有在构造器就绑定某个主题,而是从客户角度去注册观察者
  8.     # 观察者发出更新通知,观察者自行监听
  9.     # def update(self, content):
  10.     #     print(self.__class__.__name__ + '::update() [content = ' + content +']')
  11.    
  12.     pass
复制代码
抽象主题类
  1. # Subject.py 定义抽象主题类或者接口,供具体主题类继承
  2. class Subject:
  3.     def __init__(self, name):
  4.         self.name = name
  5.         self.observers = []
  6.     def get_name(self):
  7.         return self.name
  8.     def set_name(self, name):
  9.         self.name = name
  10.     def register(self, observer):
  11.         print(self.__class__.__name__ + '::register() [observer = ' +
  12.               observer.__class__.__name__ + ']')
  13.         self.observers.append(observer)
  14.     def remove(self, observer):
  15.         self.observers.remove(observer)
  16.     # 通知由具体类来实现逻辑
  17.     def notify(self, name):
  18.         pass
复制代码
具体主题类
  1. // ConcreteSubject.py 观察者主题类,也是发布者,重写具体的通知方法。不同主题可以关联不同的观察者。
  2. from src.Subject import Subject
  3. # 观察者主题类,也是发布者,重写具体的通知方法。不同主题可以关联不同的观察者。
  4. class ConcreteSubject(Subject):
  5.     # 不同的主题类有自己的通知方法,批量通知绑定的观察者
  6.     def notify(self, content):
  7.         print(self.__class__.__name__ + '::notify() [content = ' + content +
  8.               ']')
  9.         for observer in self.observers:
  10.             observer.update(content)
复制代码
测试调用
  1. import sys
  2. import os
  3. os_path = os.getcwd()
  4. sys.path.append(os_path)
  5. from src.ConcreteSubject import ConcreteSubject
  6. from src.ConcreteObserver import ConcreteObserver
  7. from src.ConcreteObserver2 import ConcreteObserver2
  8. def test():
  9.     '''
  10.     * 观察者模式应用非常广泛,主要是观察者提前绑定到发布者
  11.     * 当发布者发布消息时,批量广播通知,而无需逐一通知
  12.     * 观察者监听到消息后自己决定采取哪一种行为
  13.     '''
  14.     # 定义一个主题,也就是发布者
  15.     concrete_subject = ConcreteSubject('subject1')
  16.     # 再声明观察者,通过构造器注册到主题上
  17.     observer1 = ConcreteObserver(concrete_subject, 'observer1')
  18.     # 也可以单独给主题注册一个新的观察者
  19.     observer2 = ConcreteObserver2('observer2')
  20.     concrete_subject.register(observer2)
  21.     # 可以移除观察者对象
  22.     # concrete_subject.remove(observer1)
  23.     # 主题开始发布新通知,各观察者自动更新
  24.     concrete_subject.notify('hello, this is broadcast.')
  25. if __name__ == '__main__':
  26.     print(__file__)
  27.     print("test start:")
  28.     test()
复制代码
更多语言版本

不同语言实现设计模式:https://github.com/microwind/design-pattern

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册