【观察者设计模式详解】C/Java/JS/Go/Python/TS不同语言实现-消息
发布时间:2023-04-22 05:12:44 来源:博客园


(资料图片)

简介

观察者模式(Observer Pattern)是一种行为型模式。它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

观察者模式使用三个类Subject、Observer和Client。Subject对象带有绑定观察者到Client对象和从Client对象解绑观察者的方法。我们创建Subject类、Observer抽象类和扩展了抽象类Observer的实体类。

作用一个对象状态更新,其他依赖对象收到通知和自动更新的机制。实现模块化分离,实现主题与观察者交互对象之间的松耦合。1)观察者定义了对象之间一对多的关系。2)被观察者(主题)用一个共同的接口来更新观察者。3)观察者和被观察者用松耦合方式结合,被观察者不知道观察者的细节,只知道观察者实现了观察者接口。实现步骤创建观察者observer基础接口,包含主题和更新方法创建主题subject抽象类,包含observer列表以及添加和删除方法创建具体的主题类,实现通知方法,发布通知时轮询通知全部观察者创建多个具体观察者,与主题关联,并实现自己的更新方法客户调用时先声明主题,再将观察者分别添加到主题,当主题发布通知时,观察者自动更新UMLJava代码观察者接口
// 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 observers = new HashSet<>();   protected List 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 sysimport osos_path = os.getcwd()sys.path.append(os_path)from src.ConcreteSubject import ConcreteSubjectfrom src.ConcreteObserver import ConcreteObserverfrom src.ConcreteObserver2 import ConcreteObserver2def 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

标签: