观察者模式——订阅通知的的典型实现

  观察者模式是日常编程中常见的设计模式,主要用于在一对多的关系中,一个类状态或者数据的变化,多个类需要跟着改变的场景,这种场景中变化是一种单向的依赖关系。在实现思路上,就是让被观察的类持有一个需要通知的类的列表,当被观察者变化的时候,就可以挨个去通知观察者对象,让其根据自身的逻辑去变化。观察者模式本质上是一种事件中断机制,平时观察者不会时时刻刻去关注被观察对象,当被观察对象有变化的时候,就会自动通知过来,然后观察者再去处理对应的逻辑。

观察者模式结构图

观察者模式结构图

  • Subject:目标对象,通常会持有一个观察者的列表,并提供添加和删除观察者的功能
  • ConcreteObject:观察者的具体对象,在这里涉及到需要通知观察者的地方,会调用观察者的通知接口来通知观察者
  • Observer:观察者,这里会定义一个统一通知的方法,方便被观察对象发生变化的时候来调用
  • ConcreteObserver:观察者的具体实现

报纸订阅示例

  我们来模拟一个报纸订阅的场景,当报纸的内容更新的时候,就需要把新的报纸发给订阅的读者。

1. 观察者接口

/**
 * 观察者接口
 */
public interface Observer {
    /**
     * 数据更新后通知结构
     *
     * @param content :
     */
    void notify(String content);
}

2. 读者类

/**
 * 观察者的具体实现类
 */
public class Reader implements Observer {

    private String name;

    public Reader(String name) {
        this.name = name;
    }

    @Override
    public void notify(String content) {
        System.out.println("读者【 " + this.name + " 】接收到新的内容数据: " + content);
    }
}

3. 目标对象

/**
 * 观察的目标对象
 */
public abstract class Subject {

    protected List<Observer> observerList;

    public Subject(){
        this.observerList = new LinkedList<>();
    }

    /**
     * 追加观察者
     * @param observer :
     */
    public void attach(Observer observer){
        this.observerList.add(observer);
    }

    /**
     * 通知所有的观察者
     */
    public abstract void notifyObservers();

}

4. 报纸对象

/**
 * 被观察对象的具体实现类
 */
public class Newspaper extends Subject {

    private String content;

    public void updateContent(String content) {
        this.content = content;
        // 更新数据后通知所有的观察者
        notifyObservers();
    }

    @Override
    public void notifyObservers() {
        for (Observer observer : super.observerList) {
            observer.notify(this.content);
        }
    }
}

5. 测试方法和测试结果

public class Client {

    @Test
    public void testObserver(){
        Newspaper newspaper = new Newspaper();
        //读者订阅报纸
        newspaper.attach(new Reader("张三"));
        newspaper.attach(new Reader("李四"));
        newspaper.attach(new Reader("王五"));
        newspaper.attach(new Reader("Tom"));
        System.out.println("-----------------报纸出版----------------");
        newspaper.updateContent("第一版报纸数据");
        System.out.println("-----------------报纸出版----------------");
        newspaper.updateContent("第二版报纸");

    }
}

测试结果:

-----------------报纸出版----------------
读者【 张三 】接收到新的内容数据: 第一版报纸数据
读者【 李四 】接收到新的内容数据: 第一版报纸数据
读者【 王五 】接收到新的内容数据: 第一版报纸数据
读者【 Tom 】接收到新的内容数据: 第一版报纸数据
-----------------报纸出版----------------
读者【 张三 】接收到新的内容数据: 第二版报纸
读者【 李四 】接收到新的内容数据: 第二版报纸
读者【 王五 】接收到新的内容数据: 第二版报纸
读者【 Tom 】接收到新的内容数据: 第二版报纸

5.示例结构图

示例结构图

6.示例总结

  对比观察者模式的原始结构图和上面的示例结构图,我们可以发现原始结构图中给观察者传递的是被观察者对象,而我们示例中却是一个String。这就体现了观察者模式中的推模型和拉模型的区别,所谓的推模型,就像我们示例中一样,把具体的数据发给你,这种场景适用于观察者需要的数据比较少的情况,可以明确定义出具体的数据。所谓的拉模型就是被观察者把自己的引用传给你,想要啥,你自己去取,这种方式适用于观察者取的数据比较多,而且观察者可信的情况,因为传递过来的是引用,理论上是有被修改的风险。在具体的实践中需要根据需要选择要用拉模型还是推模型。


后记
  个人总结,欢迎转载、评论、批评指正

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值