程序员必知!观察者模式的实战应用与案例分析

Java设计模式 - 程序员古德

观察者模式定义了一对多的依赖关系,让多个观察者同时监听一个主题对象,当主题状态改变时,所有观察者都会自动收到通知并更新,以新闻发布会为例,新闻机构发布消息时,所有关注的记者和订阅者都会收到通知并进行独立处理,这就是典型的观察者模式应用,该模式实现了松耦合,主题和观察者之间不需相互了解具体实现细节。

定义

程序员必知!观察者模式的实战应用与案例分析 - 程序员古德

观察者模式它定义了对象间的一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象,当主题对象状态发生改变时,它的所有依赖者(观察者)都会自动收到通知并更新。

举个现实业务中的形象例子:想象一个新闻发布会的场景,在这个场景中,新闻机构发布了一些重要消息,而记者和订阅者(观察者)都希望尽快得到这些消息,当新闻机构发布新消息时,所有关注的记者和订阅者都会收到通知,并根据这些消息进行自己的报道或行动。

具体来说:

  1. 新闻机构:负责产生和发布新闻消息,当有新的消息时,它会通知所有关注的记者和订阅者。
  2. 记者和订阅者(观察者):他们关注新闻机构,希望在其发布新消息时得到通知,每个记者或订阅者都可以根据接收到的消息进行独立处理,比如撰写报道、更新社交媒体状态等。

在这个例子中,新闻机构和记者/订阅者之间的关系就是典型的观察者模式,新闻机构不需要知道具体有哪些记者或订阅者在关注它,它只需要在适当的时候发布消息,同样,记者和订阅者也不需要知道新闻机构是如何产生消息的,他们只需要在消息发布时得到通知并进行处理。

代码案例

程序员必知!观察者模式的实战应用与案例分析 - 程序员古德

反例

在未使用观察者模式的情况下,通常会采用直接调用或轮询的方式来通知依赖对象状态的改变,这种方式不仅增加了代码之间的耦合性,还可能导致效率低下和资源浪费,下面是一个未使用观察者模式的反例代码:

// 主题类,负责维护状态并通知观察者(但在这个例子中,并没有实现观察者模式)  
public class Subject {  
    private String state;  
      
    // 假设这是唯一关注该主题的“观察者”(实际上这并不是观察者模式的实现)  
    private ConcreteObserver observer;  
      
    public Subject(ConcreteObserver observer) {  
        this.observer = observer;  
    }  
      
    public void setState(String state) {  
        this.state = state;  
        // 直接调用观察者的更新方法  
        observer.update(state);  
    }  
      
    public String getState() {  
        return state;  
    }  
}  
  
// 观察者接口(在这个反例中,它并没有起到应有的作用)  
public interface Observer {  
    void update(String state);  
}  
  
// 具体的观察者类  
public class ConcreteObserver implements Observer {  
    private String observerState;  
      
    @Override  
    public void update(String state) {  
        this.observerState = state;  
        System.out.println("ConcreteObserver's state updated to: " + state);  
    }  
      
    public String getObserverState() {  
        return observerState;  
    }  
}  
  
// 客户端代码  
public class Client {  
    public static void main(String[] args) {  
        // 创建观察者  
        ConcreteObserver observer = new ConcreteObserver();  
        // 创建主题并将观察者传入(尽管这里传入了,但并没有利用观察者模式的优点)  
        Subject subject = new Subject(observer);  
          
        // 更改主题状态  
        subject.setState("new state");  
          
        // 输出观察者的状态  
        System.out.println("Observer's state after update: " + observer.getObserverState());  
          
        // 假设需要添加另一个观察者,但由于没有使用观察者模式,这将会很困难  
        // 不得不修改Subject类来适应新的观察者  
    }  
}

在这个例子中,Subject 类直接持有一个 ConcreteObserver 的引用,并在状态改变时直接调用它的 update 方法,这种方式的问题在于:

  1. 紧密耦合:Subject 类与 ConcreteObserver 类紧密耦合在一起,如果要添加新的观察者或者更改现有的观察者,就不得不修改 Subject 类的代码。
  2. 不易扩展:如果想要添加多个观察者,就不得不为每个观察者都添加一个引用,并在 setState 方法中调用它们的 update 方法。
  3. 违反开闭原则:对 Subject 类的任何修改都可能引入新的错误,并且违反了开闭原则。

正例

下面是一个使用观察者模式的正例代码实现,在这个例子中,有一个Subject接口,它定义了注册、移除和通知观察者的方法,ConcreteSubject类实现了这个接口,并维护了一个观察者列表,Observer是一个接口,定义了观察者更新其状态的方法,ConcreteObserver实现了这个接口,如下代码:

// 观察者接口  
public interface Observer {  
    void update(String state);  
}  
  
// 具体观察者类  
public class ConcreteObserver implements Observer {  
    private String observerState;  
      
    @Override  
    public void update(String state) {  
        // 更新观察者的状态  
        this.observerState = state;  
        System.out.println("ConcreteObserver's state updated to: " + state);  
    }  
}  
  
// 主题接口  
public interface Subject {  
    void registerObserver(Observer observer);  
    void removeObserver(Observer observer);  
    void notifyObservers(String state);  
}  
  
// 具体主题类  
import java.util.ArrayList;  
import java.util.List;  
  
public class ConcreteSubject implements Subject {  
    // 维护一个观察者列表  
    private List<Observer> observers = new ArrayList<>();  
    private String subjectState;  
      
    @Override  
    public void registerObserver(Observer observer) {  
        observers.add(observer);  
    }  
      
    @Override  
    public void removeObserver(Observer observer) {  
        observers.remove(observer);  
    }  
      
    @Override  
    public void notifyObservers(String state) {  
        // 遍历观察者列表并通知每个观察者  
        for (Observer observer : observers) {  
            observer.update(state);  
        }  
    }  
      
    // 设置主题状态的方法,状态改变时通知观察者  
    public void setState(String state) {  
        this.subjectState = state;  
        notifyObservers(state);  
    }  
      
    public String getState() {  
        return subjectState;  
    }  
}  
  
// 客户端代码  
public class Client {  
    public static void main(String[] args) {  
        // 创建具体主题和观察者  
        ConcreteSubject subject = new ConcreteSubject();  
        Observer observer = new ConcreteObserver();  
          
        // 注册观察者  
        subject.registerObserver(observer);  
          
        // 改变主题状态  
        subject.setState("new state");  
          
        // 取消注册观察者  
        subject.removeObserver(observer);  
          
        // 再次改变主题状态,此时观察者不再接收通知  
        subject.setState("another new state");  
    }  
}

运行结果将会是:

ConcreteObserver's state updated to: new state

这里展示了观察者模式的核心思想:主题维护一个观察者列表,当主题状态发生变化时,所有注册的观察者都会收到通知,这种方式降低了主题和观察者之间的耦合性,使得可以独立地改变主题或观察者,而不会影响到对方,同时,它也可以动态地添加或移除观察者,从而增加了代码的灵活性和可扩展性。

核心总结

程序员必知!观察者模式的实战应用与案例分析 - 程序员古德

观察者模式是一种行为设计模式,它能够在对象之间建立一种一对多的依赖关系,这样一来,当一个对象改变状态时,所有依赖于它的对象都会得到通知并自动更新。主要体现在,1、主题与观察者之间代码依赖度低,双方只依赖于抽象接口,而不是具体实现,易于扩展和维护,2、主题状态变化时,可以自动通知所有已注册的观察者,实现一对多的通信。在使用观察者模式时需要考虑一些注意点,1、如果观察者之间或间接地相互依赖,可能引发循环调用和系统崩溃,2、在观察者数量多或通知操作复杂时,频繁的通知可能导致性能下降,3、在多线程环境下,通知过程可能需要同步措施来避免数据不一致问题。

关注我,每天学习互联网编程技术 - 程序员古德

  • 25
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: 《程序员必知的硬核知识大全》是一本面向程序员的综合性知识手册,涵盖了各个领域的关键知识点,旨在帮助程序员提升技术水平和解决实际问题。该书以PDF格式出版,便于读者在电脑、手机等设备上随时查阅。 该书内容包括以下几个方面的硬核知识: 1. 编程语言知识:介绍了主流的编程语言,如Java、C++、Python等,包括语法、数据结构、算法等方面的内容。 2. 操作系统和计算机原理:详细介绍了操作系统的基本原理和常见问题解决方法,以及计算机组成原理和计算机网络等相关知识。 3. 数据库和存储知识:讲解了数据库设计和管理的基本原理,介绍了关系型数据库如MySQL和非关系型数据库如MongoDB等的使用方法和优化技巧。 4. 网站和网络开发知识:包括Web开发的基本原理、前后端开发技术、网络安全和性能优化等方面的内容。 5. 软件工程和开发方法论:介绍了软件工程的基本概念和常用开发方法,包括敏捷开发、测试驱动开发和持续集成等。 6. 设计模式和架构知识:详细介绍了常用的设计模式和软件架构,帮助程序员设计可维护、可扩展和高效的软件系统。 除了以上几个方面的内容,该书还涵盖了其他与程序员工作密切相关的技术和知识,如版本控制、软件部署、性能调优等。《程序员必知的硬核知识大全》适合本科或者有一定编程经验的程序员阅读,对于提高技术实力和职业发展都有很大帮助。 ### 回答2: "程序员必知的硬核知识大全 pdf"是一份提供程序员必备知识的电子书,PDF格式可以方便地在各种设备上阅读。这本书包含了各个方面的硬核知识,帮助程序员提高技术能力和解决问题的能力。 这本电子书的内容包括了数据结构和算法,编程语言,操作系统,网络通信,数据库管理等各方面的知识。对于程序员而言,这些都是非常重要的基础知识,能够帮助他们理解和设计高效的程序。 在数据结构和算法部分,程序员将学习到各种基础的数据结构,如数组、链表、栈和队列,以及常见的算法,如排序和搜索算法。这些知识对于程序的效率和性能优化至关重要。 编程语言部分将介绍多种编程语言,如C、C++、Java和Python等。这些语言在不同的领域有各自的优点和适用范围,程序员需要了解它们的特点和使用方法,以便在开发项目时选择合适的语言。 操作系统部分将深入讲解操作系统的原理和设计程序员将了解到进程管理、内存管理、文件系统等重要概念,这些对于编写具有高可靠性和高性能的程序至关重要。 网络通信部分将介绍计算机网络的基本原理和常见的协议,如TCP/IP和HTTP等。程序员需要理解网络通信的基础知识,以便与其他系统进行数据交换和通信。 数据库管理部分将详细介绍关系型数据库和非关系型数据库的原理和使用方法。程序员需要了解数据库的设计和优化,以提高数据的存储和检索效率。 总之,这本电子书涵盖了程序员必备的硬核知识,对于提高他们的技术能力和解决问题的能力非常有帮助。 ### 回答3: 《程序员必知的硬核知识大全》是一本汇集了程序员必备的核心知识的书籍,可以帮助程序员提升自己的技术水平。这本书涵盖了计算机科学的各个领域和重要概念,包括数据结构与算法、操作系统、编程语言、网络通信、数据库、Web开发、软件工程等。 在数据结构与算法部分,书介绍了常用的数据结构如链表、栈、队列以及各种排序和搜索算法,帮助程序员理解和应用这些经典的算法。在操作系统方面,书讲解了进程、线程、内存管理、文件系统等重要概念,帮助程序员深入了解计算机系统的工作原理。 在编程语言方面,书列举了多种编程语言的特性和应用场景,如C++、Java、Python等,有助于程序员选择适合自己的编程语言并掌握其特性。在网络通信部分,书介绍了TCP/IP协议、HTTP协议等重要的网络通信协议和技术,帮助程序员理解网络通信的基本原理。 此外,书还介绍了数据库的相关知识,包括关系数据库、SQL语言、数据备份与恢复等内容,有助于程序员设计和管理数据库。在Web开发方面,书介绍了前端开发、后端开发、服务器部署等关键技术,帮助程序员构建高效、安全的Web应用程序。 最后,在软件工程方面,书讲解了软件开发的生命周期、需求分析设计模式、测试和持续集成等内容,有助于程序员理解和掌握软件开发过程的重要环节。 总的来说,这本《程序员必知的硬核知识大全》提供了一站式的学习资料,涵盖了程序员必备的核心知识,可以帮助程序员系统地学习和应用这些知识,提升自己的技术能力。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员古德

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值