大话设计模式——观察者模式(二)

本文深入讲解观察者模式的核心概念及其实现方式,包括目标与观察者的单向依赖关系、推拉模型的区别,并提供了使用Java标准库实现的具体示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言:基础的观察者模式:大话设计模式——观察者模式(一)

一、再识观察者模式

1.1 目标与观察者

目标与观察者的关系是典型的一对多关系,当然,实现一对一也是可以的。
一个观察者,可以关注多个目标,一个目标也可以被多个观察者观察。
比如,小陈的女朋友和他老妈可以同时关注天气信息。而小陈的女朋友也可以同时关注天气和报纸。需要注意的是,这时的通知方法要进行区分。

1.2 单向依赖

观察者依赖目标。主动权在目标手中,观察者只有等待。

1.3 命名建议

  • 目标接口的定义,在名称后跟subject
  • 观察者接口的定义,在名称后跟observer
  • 观察者接口的更新方法,名称为update

1.4 触发通知的时机

应该先更新对应的值,在去通知观察者。

1.5 调用顺序

  • 准备阶段
    1. 创建目标对象
    2. 创建观察者对象
    3. 向目标对象注册观察者对象
  • 运行阶段
    1. 改变目标对象的状态
    2. 通知所有注册的观察者对象进行相应的处理
    3. 回调目标对象,获取相应的数据

1.6通知的顺序

通知的顺序应该是平行的,相互不能有依赖的关系

二、推拉模型

2.1 推模型

目标对象主动向观察者推送目标的详细信息
推送的信息通常是目标对象的全部或者部分数据

2.2 拉模型

目标对象在通知观察者的时候,只传递少量信息。
如果观察者需要更具体的信息,由观察者主动到目标对象中获取,相当于是观察者从目标对象中拉数据。
一般这种模型中,会把目标对象自身通过update传递给观察者(上一节的订阅天气就是一个典型的拉模型)

2.3 代码实现

首先在Observer接口中,新增一个方法,按需求定制相应方法。

    /**
     * 推模型,按需定制
     * @param content 天气内容
     */
    void updateWeatherContent(String content);

在ConcreatObserver中,实现此方法

    @Override
    public void updateWeatherContent(String content) {
        weatherContent = content;
        System.out.println(observerName+"收到了"+weatherContent+","+remindThing);
    }

再来到WeatherSubject中,修改notifyObservers方法

    /**
     * 通知所有已经订阅了天气的人
     * @param content 天气信息
     */
    protected void notifyObservers(String content){
        for(Observer observer:observers){
            observer.updateWeatherContent(content);
        }
    }

最后,来到ConcreatWeatherSubject类,修改setWeatherContent方法,传入天气信息。

    public void setWeatherContent(String weatherContent) {
        this.weatherContent = weatherContent;
        //天气更新,通知所有订阅天气的观察者
        this.notifyObservers(weatherContent);
    }

2.4 比较

  • 推模型是假定目标知道观察者需要的数据,观察者难以复用
  • 拉模型是目标对象不知道观察者要什么样的数据,就将自身传给观察者

三、利用Java提供的观察者实现

3.1 目标类

我们的目标类继承Java提供的Observable

public class ConcreteWeatherSubject extends Observable {
    //天气情况
    private String content;

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
        //通知所有观察者
        //Java中的Observer模式中,这句话不可少
        this.setChanged();
        //推方法
        this.notifyObservers(content);
        //拉方法
        //this.notifyObservers();
    }
}

3.2 观察者

实现Java提供的Observer接口,实现update方法。其中o为传递过来的目标对象(拉方式),arg为推过来的内容(推方式)。

public class ConcreteObserver implements Observer{
    //观察者名称变量
    private String observerName;

    @Override
    public void update(Observable o, Object arg) {
        //推方式
        System.out.println(observerName + "收到了消息,推送过来的是" + arg);

        //拉方式
        System.out.println(observerName + "收到了消息,主动到目标对象"
                + "中去拉消息,拉的内容是" + 
                ((ConcreteWeatherSubject)o).getContent());

    }

    public String getObserverName() {
        return observerName;
    }

    public void setObserverName(String observerName) {
        this.observerName = observerName;
    }

}

3.3 测试类

public class Client {
    public static void main(String[] args) {
        //创建天气
        ConcreteWeatherSubject subject = new ConcreteWeatherSubject();
        //创建观察者
        ConcreteObserver girl = new  ConcreteObserver();
        girl.setObserverName("GF");
        ConcreteObserver mom = new  ConcreteObserver();
        mom.setObserverName("MOM");

        //注册
        subject.addObserver(girl);
        subject.addObserver(mom);

        //目标更新天气
        subject.setContent("台风14级");
    }
}

四、优缺点

4.1 优点

  • 实现了观察者和目标之间的抽象耦合
  • 实现了动态联动
  • 支持广播通信

4.2 缺点

  • 可能引起无谓操作(一些观察者可能不需要某些信息,也可能引起误更新)

参考:大话设计模式——观察者模式(二)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值