【再谈计划模式】观察者模式~对象间依赖关系的信使

火影  论坛元老 | 2025-1-10 15:10:12 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 1017|帖子 1017|积分 3051

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x

一、弁言

        在软件工程、软件开辟的天下里,计划模式如同建筑蓝图中的经典结构,资助开辟者构建更加灵活、可维护和可扩展的软件系统。观察者模式就是其中一种极为重要的举动型计划模式,它在处置处罚对象间的一对多关系时展现出独特的魅力。

二、界说与描述


        观察者模式界说了对象之间的一种一对多依赖关系。其中有一个被观察的对象(称为主题Subject)和多个观察该对象的观察者(Observer)。主题对象负责维护一组观察者对象,并在自身状态发生改变时关照全部观察者。这种模式使得对象之间的耦合度低沉,主题和观察者可以独立地进行扩展和修改。

三、抽象背景

        在很多实际的软件场景中,存在着对象状态变化必要关照其他对象的需求。例如,在一个消息发布系统中,当有新的消息发布(消息对象状态改变)时,订阅了该消息频道的用户(观察者)必要实时得到关照;或者在一个游戏开辟中,当游戏脚色的某些属性(如生命值、位置等)发生变化时,与之相干的UI界面元素(观察者)必要更新表现。


四、适用场景与实际题目办理




  • 事件驱动系统

    • 在图形用户界面(GUI)开辟中,用户的操作(如点击按钮、输入文本等)会触发事件。这些事件可以看作是主题的状态变化,而处置处罚这些事件的各个组件(如菜单更新、数据表现等)就是观察者。通过观察者模式,可以很方便地实现事件的分发和处置处罚,使差别的组件能够独立地相应事件。




  • 股票市场监测

    • 当股票代价发生变化(主题状态改变)时,多个投资者(观察者)必要得到关照以便做出相应的决策。利用观察者模式可以高效地实现这种关照机制,而不必要在股票代价变化的代码中硬编码每个投资者的关照逻辑。


五、观察者模式的实际生活的例子




  • 社交媒体平台

    • 当一个用户(主题)发布了一条新的动态时,他的好友(观察者)会收到关照。这里,用户是被观察的对象,好友们是观察者。社交平台负责维护好友关系(即主题中的观察者列表),并在用户发布新动态时关照全部好友。




  • 景象站与订阅者

    • 景象站(主题)负责网络景象数据并检测天气状态的变化。当天气状态发生变化(如温度、湿度、气压等数据变化)时,景象站会关照全部订阅了景象信息的用户(观察者),如农民、飞行员、户外运动爱好者等。



六、初衷与题目办理



  • 初衷

    • 观察者模式的初衷是为了实现对象之间的松耦合关系。在没有这种模式的情况下,如果一个对象的状态变化必要关照其他对象,大概会导致高度耦合的代码,即变化的对象必要直接调用其他对象的方法来关照它们。这使得代码难以维护和扩展,由于任何一个相干对象的改变都大概影响到其他对象。

  • 题目办理

    • 通过观察者模式,主题和观察者之间通过抽象的接口进行交互。主题只必要维护一个观察者列表,并在状态变化时调用观察者的抽象关照方法。如许,主题不必要知道具体的观察者范例,观察者也不必要知道主题的具体实现细节。当有新的观察者或主题必要参加系统时,只必要实现相应的接口即可,不会影响到其他部门的代码。


七、代码示例


Java示例

  1. import java.util.ArrayList;
  2. import java.util.List;
  3. // 观察者接口
  4. interface Observer {
  5.     void update(String message);
  6. }
  7. // 主题类
  8. class Subject {
  9.     private List<Observer> observers = new ArrayList<>();
  10.     private String state;
  11.     public void attach(Observer observer) {
  12.         observers.add(observer);
  13.     }
  14.     public void detach(Observer observer) {
  15.         observers.remove(observer);
  16.     }
  17.     public void setState(String state) {
  18.         this.state = state;
  19.         notifyAllObservers();
  20.     }
  21.     private void notifyAllObservers() {
  22.         for (Observer observer : observers) {
  23.             observer.update(state);
  24.         }
  25.     }
  26. }
  27. // 具体观察者类
  28. class ConcreteObserver implements Observer {
  29.     private String name;
  30.     public ConcreteObserver(String name) {
  31.         this.name = name;
  32.     }
  33.     @Override
  34.     public void update(String message) {
  35.         System.out.println(name + " received message: " + message);
  36.     }
  37. }
  38. public class Main {
  39.     public static void main(String[] args) {
  40.         Subject subject = new Subject();
  41.         Observer observer1 = new ConcreteObserver("Observer 1");
  42.         Observer observer2 = new ConcreteObserver("Observer 2");
  43.         subject.attach(observer1);
  44.         subject.attach(observer2);
  45.         subject.setState("New state!");
  46.     }
  47. }
复制代码
类图:

  Subject类与Observer接口之间是一对多的关系(Subject可以有多个Observer)ConcreteObserver类实现了Observer接口。 



C++示例

  1. #include <iostream>
  2. #include <vector>
  3. // 观察者抽象类
  4. class Observer {
  5. public:
  6.     virtual void update(std::string message) = 0;
  7. };
  8. // 主题类
  9. class Subject {
  10. private:
  11.     std::vector<Observer*> observers;
  12.     std::string state;
  13. public:
  14.     void attach(Observer* observer) {
  15.         observers.push_back(observer);
  16.     }
  17.     void detach(Observer* observer) {
  18.         for (auto it = observers.begin(); it!= observers.end(); ++it) {
  19.             if (*it == observer) {
  20.                 observers.erase(it);
  21.                 break;
  22.             }
  23.         }
  24.     }
  25.     void setState(std::string state) {
  26.         this.state = state;
  27.         notifyAllObservers();
  28.     }
  29.     void notifyAllObservers() {
  30.         for (auto observer : observers) {
  31.             observer->update(state);
  32.         }
  33.     }
  34. };
  35. // 具体观察者类
  36. class ConcreteObserver : public Observer {
  37. private:
  38.     std::string name;
  39. public:
  40.     ConcreteObserver(std::string name) : name(name) {}
  41.     void update(std::string message) override {
  42.         std::cout << name << " received message: " << message << std::endl;
  43.     }
  44. };
  45. int main() {
  46.     Subject subject;
  47.     Observer* observer1 = new ConcreteObserver("Observer 1");
  48.     Observer* observer2 = new ConcreteObserver("Observer 2");
  49.     subject.attach(observer1);
  50.     subject.attach(observer2);
  51.     subject.setState("New state!");
  52.     return 0;
  53. }
复制代码
Python示例

  1. # 观察者抽象类
  2. class Observer:
  3.     def update(self, message):
  4.         pass
  5. # 主题类
  6. class Subject:
  7.     def __init__(self):
  8.         self.observers = []
  9.         self.state = None
  10.     def attach(self, observer):
  11.         self.observers.append(observer)
  12.     def detach(self, observer):
  13.         self.observers.remove(observer)
  14.     def setState(self, state):
  15.         self.state = state
  16.         self.notifyAllObservers()
  17.     def notifyAllObservers(self):
  18.         for observer in self.observers:
  19.             observer.update(self.state)
  20. # 具体观察者类
  21. class ConcreteObserver(Observer):
  22.     def __init__(self, name):
  23.         self.name = name
  24.     def update(self, message):
  25.         print(f"{self.name} received message: {message}")
  26. if __name__ == "__main__":
  27.     subject = Subject()
  28.     observer1 = ConcreteObserver("Observer 1")
  29.     observer2 = ConcreteObserver("Observer 2")
  30.     subject.attach(observer1)
  31.     subject.attach(observer2)
  32.     subject.setState("New state!")
复制代码
Go示例

  1. package main
  2. import (
  3.     "fmt"
  4. )
  5. // 观察者接口
  6. type Observer interface {
  7.     update(message string)
  8. }
  9. // 主题结构体
  10. type Subject struct {
  11.     observers []Observer
  12.     state     string
  13. }
  14. // 附加观察者
  15. func (s *Subject) attach(observer Observer) {
  16.     s.observers = append(s.observers, observer)
  17. }
  18. // 分离观察者
  19. func (s *Subject) detach(observer Observer) {
  20.     for i, obs := range s.observers {
  21.         if obs == observer {
  22.             s.observers = append(s.observers[:i], s.observers[i+1:]...)
  23.             break
  24.         }
  25.     }
  26. }
  27. // 设置状态并通知观察者
  28. func (s *Subject) setState(state string) {
  29.     s.state = state
  30.     s.notifyAllObservers()
  31. }
  32. // 通知所有观察者
  33. func (s *Subject) notifyAllObservers() {
  34.     for _, observer := range s.observers {
  35.         observer.update(s.state)
  36.     }
  37. }
  38. // 具体观察者结构体
  39. type ConcreteObserver struct {
  40.     name string
  41. }
  42. // 具体观察者实现更新方法
  43. func (co *ConcreteObserver) update(message string) {
  44.     fmt.Printf("%s received message: %s\n", co.name, message)
  45. }
  46. func main() {
  47.     subject := Subject{}
  48.     observer1 := ConcreteObserver{name: "Observer 1"}
  49.     observer2 := ConcreteObserver{name: "Observer 2"}
  50.     subject.attach(&observer1)
  51.     subject.attach(&observer2)
  52.     subject.setState("New state!")
  53. }
复制代码
八、观察者模式的优缺点



  • 长处

    • 松耦合:主题和观察者之间是松耦合的关系。主题不必要知道观察者的具体实现,只必要调用观察者的抽象接口。这使得在系统中添加或删除观察者非常容易,不会影响到主题的代码。
    • 可扩展性:可以很容易地增长新的观察者,只必要实现观察者接口即可。同样,主题也可以在不影响观察者的情况下进行扩展。
    • 支持广播通讯:一个主题可以关照多个观察者,实现了一对多的消息传递,适合于必要将信息广播给多个对象的场景。

  • 缺点

    • 大概存在关照次序题目:如果有多个观察者,当主题关照观察者时,大概会存在关照次序不确定的题目。这在某些对次序有严格要求的场景下大概会导致题目。
    • 性能开销:如果观察者数量较多,当主题状态发生变化时,关照全部观察者大概会带来一定的性能开销。特别是在观察者的更新操作比力复杂时,这种开销会更加显着。



九、观察者模式的升级版




  • 事件委托模型

    • 在传统的观察者模式中,主题直接关照全部的观察者。而在事件委托模型中,引入了事件源、事件和事件处置处罚步伐的概念。事件源(雷同于主题)产生事件,事件包含了关于状态变化的信息,事件处置处罚步伐(雷同于观察者)负责处置处罚事件。事件委托模型更加灵活,可以根据事件的范例、优先级等因向来决定怎样处置处罚事件,而不是简朴地关照全部观察者。

  • 反应式编程中的观察者模式扩展

    • 在反应式编程(如RxJava、ReactiveX等)中,观察者模式得到了进一步的扩展。反应式编程关注的是数据的活动和异步处置处罚。在这种模式下,观察者可以对数据的变化做出反应,并且可以组合、转换和过滤数据。例如,在RxJava中,可以利用操作符来对数据流进行操作,然后再将处置处罚后的结果关照给观察者。这使得观察者模式在处置处罚异步和复杂的数据处置处罚场景时更加高效和灵活。




免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

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

本版积分规则

火影

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表