【重温设计模式】观察者模式及其Java示例

观察者模式的概念和原理

在编程世界中,设计模式作为一种解决问题的策略,它的存在就如同人类语言中的成语,是一种经过时间考验的有效解决方案。

观察者模式就是其中一种重要的设计模式,它在很多场景中都有着广泛的应用。那么,什么是观察者模式呢?观察者模式,又被称为发布-订阅模式,其基本概念是定义了对象之间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。

它的设计原理就像是一场戏,主角(主题)在舞台上表演,观众(观察者)在台下观看。当主角的表演发生变化时,观众能立即感知到这种变化。在编程领域,观察者模式的应用场景十分广泛,比如GUI中的事件处理,社交网络中的消息推送,甚至是股票交易系统中的价格更新等等。

java 复制代码
class OneMoreSubject {
    private List<Observer> observers = new ArrayList<>();

    public void addObserver(Observer observer) {
        observers.add(observer);
    }

    public void notifyAllObservers() {
        for (Observer observer : observers) {
            observer.update();
        }
    }
}

以上是一个简单的观察者模式的Java代码示例,OneMoreSubject类就是我们的主题,它维护了一个观察者列表。当有新的观察者加入时,我们通过addObserver方法将其加入到观察者列表中。当主题的状态发生变化时,我们通过notifyAllObservers方法通知所有的观察者。这样,我们就实现了观察者模式的基本框架。接下来,我们将详细解释观察者模式的主要组成部分,包括主题(Subject)和观察者(Observer),并解释它们的角色和互动方式。

观察者模式的组成部分

在探讨观察者模式的具体应用之前,我们首先需要理解它的主要组成部分。观察者模式主要由两个角色构成,它们分别是主题(Subject)和观察者(Observer)。主题可以被视为数据的提供者,它持有一些重要的状态信息。当这些状态发生变化时,主题会通知所有的观察者。观察者则是数据的接收者,它们订阅了主题,并在主题状态变化时接收通知。主题与观察者之间的关系,就像是一份报纸与它的订阅者,或者是一个B站UP主与它的关注者。

java 复制代码
public interface Subject {
    void registerObserver(Observer o);
    void removeObserver(Observer o);
    void notifyObservers();
}

public interface Observer {
    void update(OneMore oneMore);
}

在这个简单的Java代码示例中,Subject接口声明了注册(register)、移除(remove)和通知(notify)观察者的方法,而Observer接口则声明了一个更新(update)方法,用于接收主题的状态变化通知。这就是观察者模式的基本构成,通过这种方式,我们可以将数据的提供者和接收者解耦,使得在数据状态变化时,可以灵活地通知到所有关注此变化的观察者。

有了对观察者模式组成部分的理解,我们就可以进一步探讨如何在实际项目中应用观察者模式了。在下一部分,我们将通过一个电子商务系统的Java实例,展示观察者模式的工作流程。

观察者模式的Java实例

在我们刚刚探讨过的观察者模式的主要组成部分------主题(Subject)和观察者(Observer)之后,现在让我们通过一个具体的Java实例来看看观察者模式是如何在实际项目中发挥作用的。假设我们正在开发一个电子商务系统,当一个商品的库存数量发生变化时,需要通知相关的销售人员和采购人员,这就是一个典型的观察者模式的应用场景。

首先,我们定义一个Subject类,这个类有一个OneMore的商品库存数量,当这个数量发生变化时,就需要通知所有的观察者。

java 复制代码
public class Subject {
    private int OneMore;
    private List<Observer> observers = new ArrayList<>();

    public void setOneMore(int OneMore) {
        this.OneMore = OneMore;
        notifyAllObservers();
    }

    public void attach(Observer observer){
        observers.add(observer);      
    }

    public void notifyAllObservers(){
        for (Observer observer : observers) {
            observer.update();
        }
    } 
}

然后,我们定义一个Observer接口和两个实现这个接口的类:SalesObserverPurchaseObserver,分别代表销售人员和采购人员。

java 复制代码
public interface Observer {
    void update();
}

public class SalesObserver implements Observer {
    public void update() {
        System.out.println("SalesObserver: OneMore's stock has changed.");
    }
}

public class PurchaseObserver implements Observer {
    public void update() {
        System.out.println("PurchaseObserver: OneMore's stock has changed.");
    }
}

OneMore的库存数量发生变化时,Subject类就会调用notifyAllObservers方法,通知所有的观察者。这样,无论是销售人员还是采购人员,都能够得到库存变化的通知,从而做出相应的行动。这就是观察者模式的工作流程。
implements implements contains 1 * Subject -int OneMore -List<Observer> observers +setOneMore(int OneMore) +attach(Observer observer) +notifyAllObservers() <<interface>> Observer +update() SalesObserver +update() PurchaseObserver +update()

然而,任何设计模式都有其适用的场景,也有其优缺点。接下来,我们将探讨观察者模式的优缺点,以及在何种情况下应该使用观察者模式。

观察者模式的优缺点

在我们深入探讨观察者模式的优缺点之前,让我们先来描绘一下这种模式的特色。观察者模式是一种行为设计模式,它允许对象在状态发生变化时通知其依赖对象,而无需它们之间直接耦合。这种模式的主要优点是它支持单向依赖,这意味着主题并不关心观察者的具体实现,只关心观察者是否遵循了预定义的接口。这种设计大大提高了代码的灵活性和可重用性。

然而,这种模式也有其缺点。首先,观察者模式可能导致过度通信。当主题的状态发生改变时,所有的观察者都会被通知,即使他们对该变化没有任何兴趣。其次,如果观察者和主题之间存在循环依赖,可能会导致系统陷入无限循环。最后,如果观察者的处理时间过长,可能会阻塞主题的进程。

对于何时使用观察者模式,一般的建议是当你希望在对象的状态改变时,能够通知其他对象,但又不希望这些对象之间存在直接依赖关系时,可以考虑使用观察者模式。例如,一个邮件订阅系统就可以使用观察者模式,当新的邮件到达时,所有订阅者都会收到通知。

总结

总的来说,观察者模式是一种强大的设计模式,它能够帮助我们在系统中实现松耦合的对象间通信。通过这种模式,我们可以使得一个对象的状态变化能够通知到其他的对象,而不需要这些对象之间存在直接的联系。这样,我们就可以实现对象间的动态交互,使得系统更加灵活和可扩展。

但是,我们也需要注意,观察者模式并不是万能的。在某些情况下,它可能会导致过度通信,或者造成系统的循环依赖。因此,我们在使用观察者模式时,需要仔细考虑其适用性,确保它能够帮助我们解决问题,而不是引入新的问题。

我们可能会遇到许多需要使用观察者模式的场景。比如,我们可能需要实现一个社交网络的消息推送系统,或者一个电子商务网站的库存管理系统。在这些场景中,观察者模式都能够发挥其强大的作用。

然而,设计模式只是工具,而不是目标。我们的最终目标,是通过使用这些工具,来编写出高效、可维护、可扩展的代码。因此,我们应该根据实际的需求和场景,灵活地选择和使用设计模式,而不是死板地套用。

相关推荐
跳动的梦想家h2 小时前
黑马点评 秒杀下单出现的问题:服务器异常---java.lang.NullPointerException: null(已解决)
java·开发语言·redis
苹果醋32 小时前
前端面试之九阴真经
java·运维·spring boot·mysql·nginx
博风2 小时前
设计模式:7、策略模式(政策)
设计模式·策略模式
哎呦没2 小时前
Spring Boot OA:企业办公自动化的高效路径
java·spring boot·后端
真心喜欢你吖2 小时前
Spring Boot与MyBatis-Plus的高效集成
java·spring boot·后端·spring·mybatis
2402_857589362 小时前
企业办公自动化:Spring Boot OA管理系统开发与实践
java·spring boot·后端
G丶AEOM2 小时前
JVM逃逸分析机制
java·jvm
无聊写博客3 小时前
JDK、JRE、JVM的区别
java·开发语言·jvm
message丶小和尚3 小时前
SpringBoot升级全纪录之项目启动
java·spring boot·mybatis
Allen Bright3 小时前
IDEA配置本地maven
java·maven·intellij-idea