• 设计模式——14. 观察者模式


    1. 说明

    观察者模式(Observer Pattern)是一种行为型设计模式,用于定义对象之间的一对多依赖关系,使得当一个对象的状态发生改变时,所有依赖于它的对象都能够自动收到通知并更新自己的状态,以保持与被观察对象的同步。观察者模式也被称为发布-订阅模式。

    观察者模式包含以下关键角色:

    1. Subject(被观察者):Subject 是被观察对象,它维护一组观察者对象,并提供方法来添加、删除和通知观察者。当 Subject 的状态发生改变时,它会通知所有注册的观察者。
    2. Observer(观察者):Observer 是观察者对象,它定义了一个更新方法(通常命名为 update),用于接收被观察对象的通知并执行相应的操作。多个观察者可以订阅同一个被观察者。
    3. ConcreteSubject(具体被观察者):ConcreteSubject 是具体的被观察对象,它实现了 Subject 接口,负责维护状态并在状态发生改变时通知观察者。
    4. ConcreteObserver(具体观察者):ConcreteObserver 是具体的观察者对象,它实现了 Observer 接口,并定义了在接收到通知时要执行的具体操作。

    观察者模式的优点包括:

    • 解耦性:被观察者和观察者之间的关系是松散耦合的,它们可以独立变化,不会相互影响。
    • 可扩展性:可以方便地添加新的观察者,无需修改被观察者的代码。
    • 通知机制:当被观察者的状态发生改变时,所有注册的观察者会自动收到通知,不需要手动轮询。

    观察者模式是一种非常有用的模式,它可以帮助实现对象之间的松散耦合,提高系统的可维护性和可扩展性。

    2. 使用的场景

    观察者模式在以下情况下特别有用,这些场景通常涉及到对象之间的状态变化需要通知其他对象或组件:

    1. 事件处理和 GUI 开发: 在图形用户界面(GUI)应用程序中,用户交互和事件处理是观察者模式的经典用例。例如,按钮点击事件、窗口关闭事件、鼠标移动事件等都可以通过观察者模式来处理。
    2. 消息通知系统: 观察者模式用于构建发布-订阅模型的消息通知系统,例如电子邮件通知、新闻订阅、社交媒体通知等。当有新消息或更新时,通知系统会通知所有订阅者。
    3. 股票市场和金融领域: 在股票市场中,股票价格的变化会通知所有订阅该股票的投资者。金融领域中也有类似的应用,如外汇汇率变化通知。
    4. 分布式系统: 在分布式系统中,观察者模式可以用于实现事件驱动的通信机制。当一个节点的状态发生变化时,可以通知其他节点或服务。
    5. 日志记录和监控系统: 观察者模式可以用于监控系统中,例如服务器日志记录和性能监控。当系统状态或日志条目发生变化时,观察者可以记录或报警。
    6. 实时数据更新: 当需要在多个地方保持数据同步时,观察者模式可以用于实时数据更新,确保所有订阅者都能及时获得最新数据。
    7. 游戏开发: 在游戏开发中,观察者模式常用于处理游戏中的事件和状态变化,如角色状态变化、敌人出现等。

    总之,观察者模式适用于任何需要对象之间的松散耦合、动态通信和状态同步的场景。它有助于将系统组件分离,提高代码的可维护性和可扩展性,并使系统更容易适应变化。

    3. 应用例子

    以下是一个使用 Python 实现的观察者模式示例,模拟了一个简单的股票市场通知系统:

    # 定义观察者接口
    class Observer:
        def update(self, message):
            pass
    
    # 定义具体观察者类
    class StockInvestor(Observer):
        def __init__(self, name):
            self.name = name
    
        def update(self, message):
            print(f"{self.name} 收到股票市场通知:{message}")
    
    # 定义被观察者类
    class StockMarket:
        def __init__(self):
            self.investors = []  # 存储观察者
    
        def add_investor(self, investor):
            self.investors.append(investor)
    
        def remove_investor(self, investor):
            self.investors.remove(investor)
    
        def notify_investors(self, message):
            for investor in self.investors:
                investor.update(message)
    
    if __name__ == "__main__":
        # 创建被观察者对象
        stock_market = StockMarket()
    
        # 创建具体观察者并注册到被观察者
        investor1 = StockInvestor("投资者1")
        investor2 = StockInvestor("投资者2")
    
        stock_market.add_investor(investor1)
        stock_market.add_investor(investor2)
    
        # 发送通知给观察者
        stock_market.notify_investors("股票价格上涨!")
    
        # 移除一个观察者
        stock_market.remove_investor(investor2)
    
        # 再次发送通知给观察者
        stock_market.notify_investors("股票价格下跌!")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    4. 实现要素

    观察者模式的实现要素包括以下几个部分:

    1. Subject(被观察者): 被观察者是一个具体的对象,它维护一组观察者对象的引用,提供方法用于添加、删除和通知观察者。通常,被观察者会维护一个状态,当状态发生变化时,会通知所有观察者。
    2. Observer(观察者): 观察者是一个接口或抽象类,定义了一个更新方法(通常命名为 update),该方法在被观察者状态发生变化时被调用。具体的观察者类实现该接口,以便接收被观察者的通知并执行相应的操作。
    3. ConcreteSubject(具体被观察者): 具体被观察者是被观察者接口的实现类,它负责维护状态并在状态发生改变时通知观察者。通常,具体被观察者会维护一个观察者列表,用于存储注册的观察者。
    4. ConcreteObserver(具体观察者): 具体观察者是观察者接口的实现类,它定义了在接收到通知时要执行的具体操作。每个具体观察者都可以有不同的实现。

    5. UML图

    在这里插入图片描述

    • Subject 接口定义了 attach(添加观察者)、detach(删除观察者)和 notify(通知观察者)等方法。
    • ConcreteSubject 类实现了 Subject 接口,它维护了一个观察者列表,并在状态发生变化时调用 notify 方法通知观察者。
    • Observer 接口定义了 update 方法,用于在被观察者状态发生变化时接收通知。
    • ConcreteObserver 类实现了 Observer 接口,它包含具体的操作逻辑,以响应被观察者的通知。

    观察者模式的关键思想是被观察者与观察者之间的松散耦合,被观察者不需要知道观察者的具体实现,只需要知道它们实现了共同的接口。这种松散耦合使得系统更易于扩展和维护,符合面向对象设计原则中的依赖倒置原则。

    6. Java/golang/javascrip/C++ 等语言实现方式

    6.1 Java实现

    上述例子用Java语言实现示例如下:

    import java.util.ArrayList;
    import java.util.List;
    
    // 定义观察者接口
    interface Observer {
        void update(String message);
    }
    
    // 定义具体观察者类
    class StockInvestor implements Observer {
        private String name;
    
        public StockInvestor(String name) {
            this.name = name;
        }
    
        @Override
        public void update(String message) {
            System.out.println(name + " 收到股票市场通知:" + message);
        }
    }
    
    // 定义被观察者类
    class StockMarket {
        private List investors = new ArrayList<>();
    
        public void addInvestor(Observer investor) {
            investors.add(investor);
        }
    
        public void removeInvestor(Observer investor) {
            investors.remove(investor);
        }
    
        public void notifyInvestors(String message) {
            for (Observer investor : investors) {
                investor.update(message);
            }
        }
    }
    
    public class ObserverPatternExample {
        public static void main(String[] args) {
            // 创建被观察者对象
            StockMarket stockMarket = new StockMarket();
    
            // 创建具体观察者并注册到被观察者
            Observer investor1 = new StockInvestor("投资者1");
            Observer investor2 = new StockInvestor("投资者2");
    
            stockMarket.addInvestor(investor1);
            stockMarket.addInvestor(investor2);
    
            // 发送通知给观察者
            stockMarket.notifyInvestors("股票价格上涨!");
    
            // 移除一个观察者
            stockMarket.removeInvestor(investor2);
    
            // 再次发送通知给观察者
            stockMarket.notifyInvestors("股票价格下跌!");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63

    6.2 Golang实现

    上述例子用golang实现示例如下:

    package main
    
    import "fmt"
    
    // 定义观察者接口
    type Observer interface {
            Update(message string)
    }
    
    // 定义具体观察者结构体
    type StockInvestor struct {
            Name string
    }
    
    func (si *StockInvestor) Update(message string) {
            fmt.Printf("%s 收到股票市场通知:%s\n", si.Name, message)
    }
    
    // 定义被观察者结构体
    type StockMarket struct {
            investors []Observer
    }
    
    func (sm *StockMarket) AddInvestor(investor Observer) {
            sm.investors = append(sm.investors, investor)
    }
    
    func (sm *StockMarket) RemoveInvestor(investor Observer) {
            for i, obs := range sm.investors {
                    if obs == investor {
                            sm.investors = append(sm.investors[:i], sm.investors[i+1:]...)
                            break
                    }
            }
    }
    
    func (sm *StockMarket) NotifyInvestors(message string) {
            for _, investor := range sm.investors {
                    investor.Update(message)
            }
    }
    
    func main() {
            // 创建被观察者对象
            stockMarket := &StockMarket{}
    
            // 创建具体观察者并注册到被观察者
            investor1 := &StockInvestor{Name: "投资者1"}
            investor2 := &StockInvestor{Name: "投资者2"}
    
            stockMarket.AddInvestor(investor1)
            stockMarket.AddInvestor(investor2)
    
            // 发送通知给观察者
            stockMarket.NotifyInvestors("股票价格上涨!")
    
            // 移除一个观察者
            stockMarket.RemoveInvestor(investor2)
    
            // 再次发送通知给观察者
            stockMarket.NotifyInvestors("股票价格下跌!")
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62

    6.3 Javascript实现

    上述例子用javascript实现示例如下:

    // 定义观察者接口
    class Observer {
      update(message) {}
    }
    
    // 定义具体观察者类
    class StockInvestor extends Observer {
      constructor(name) {
        super();
        this.name = name;
      }
    
      update(message) {
        console.log(`${this.name} 收到股票市场通知:${message}`);
      }
    }
    
    // 定义被观察者类
    class StockMarket {
      constructor() {
        this.investors = [];
      }
    
      addInvestor(investor) {
        this.investors.push(investor);
      }
    
      removeInvestor(investor) {
        const index = this.investors.indexOf(investor);
        if (index !== -1) {
          this.investors.splice(index, 1);
        }
      }
    
      notifyInvestors(message) {
        this.investors.forEach((investor) => {
          investor.update(message);
        });
      }
    }
    
    // 创建被观察者对象
    const stockMarket = new StockMarket();
    
    // 创建具体观察者并注册到被观察者
    const investor1 = new StockInvestor("投资者1");
    const investor2 = new StockInvestor("投资者2");
    
    stockMarket.addInvestor(investor1);
    stockMarket.addInvestor(investor2);
    
    // 发送通知给观察者
    stockMarket.notifyInvestors("股票价格上涨!");
    
    // 移除一个观察者
    stockMarket.removeInvestor(investor2);
    
    // 再次发送通知给观察者
    stockMarket.notifyInvestors("股票价格下跌!");
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59

    6.4 C++实现

    上述例子用C++实现如下:

    #include 
    #include 
    
    // 定义观察者基类
    class Observer {
    public:
        virtual void update(const std::string& message) = 0;
    };
    
    // 定义具体观察者类
    class StockInvestor : public Observer {
    public:
        StockInvestor(const std::string& name) : name(name) {}
    
        void update(const std::string& message) override {
            std::cout << name << " 收到股票市场通知:" << message << std::endl;
        }
    
    private:
        std::string name;
    };
    
    // 定义被观察者类
    class StockMarket {
    public:
        void addInvestor(Observer* investor) {
            investors.push_back(investor);
        }
    
        void removeInvestor(Observer* investor) {
            for (auto it = investors.begin(); it != investors.end(); ++it) {
                if (*it == investor) {
                    investors.erase(it);
                    break;
                }
            }
        }
    
        void notifyInvestors(const std::string& message) {
            for (auto investor : investors) {
                investor->update(message);
            }
        }
    
    private:
        std::vector investors;
    };
    
    int main() {
        // 创建被观察者对象
        StockMarket stockMarket;
    
        // 创建具体观察者并注册到被观察者
        StockInvestor investor1("投资者1");
        StockInvestor investor2("投资者2");
    
        stockMarket.addInvestor(&investor1);
        stockMarket.addInvestor(&investor2);
    
        // 发送通知给观察者
        stockMarket.notifyInvestors("股票价格上涨!");
    
        // 移除一个观察者
        stockMarket.removeInvestor(&investor2);
    
        // 再次发送通知给观察者
        stockMarket.notifyInvestors("股票价格下跌!");
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70

    7. 练习题

    假设你正在开发一个简单的天气应用程序,用户可以订阅并接收天气预报通知。设计一个观察者模式来实现这个应用程序。

    要求:

    1. 创建一个 WeatherData 类,作为被观察者,它可以存储当前的天气信息(例如温度、湿度、气压)。
    2. 创建一个 Observer 接口,定义一个 update 方法,以便观察者可以在天气信息变化时收到通知。
    3. 创建具体观察者类 CurrentConditionsDisplay,它实现了 Observer 接口,可以显示当前的温度、湿度和气压。
    4. 在 WeatherData 类中,实现注册观察者、移除观察者和通知观察者的方法。
    5. 编写一个测试程序,创建一个 WeatherData 对象和一个 CurrentConditionsDisplay 对象,然后模拟天气信息的变化,观察 CurrentConditionsDisplay 是否能够接收并显示最新的天气信息。

    你可以在评论区里或者私信我回复您的答案,这样我或者大家都能帮你解答,期待着你的回复~

  • 相关阅读:
    软件测试-面试题总结(自动化)
    阿里巴巴面试题- - -Java体系最新面试题(2022内部资料)
    手把手带你玩转Spark机器学习-使用Spark构建回归模型
    java.sql.SQLException: ORA-28000: the account is locked
    2019银川F,ccpc威海D - Sternhalma 2022
    ubuntu 爬虫任务相关常用命令
    支付场景。
    Linux bash脚本编程学习
    大数据Eureka的使用以及应用场景详解
    Docker | docker容器导出以及常见问题的处理
  • 原文地址:https://blog.csdn.net/guohuang/article/details/133669280