观察者模式

 介绍

观察者模式是一个使用率非常高的模式,这个模式的一个重要作用就是将被观察者和观察者解耦,使得它们之间的依赖性更小,甚至做到毫无依赖。

定义

观察者模式定义对象间一种一对多的依赖关系,使得当每一个对象改变状态时,则所有依赖于它的对象都会得到通知并被自动更新。

使用场景

(1)关联行为场景,需要注意的是,关联行为是可拆分的,而不是组合关系

(2)事件多级出发场景

(3)跨系统的消息交换场景,如消息队列,事件总线的处理机制

类图

角色介绍:

  • Subject - 抽象主题,也就是被观察者(Observable)的角色,抽象主题把所有观察者对象的引用保存在一个集合里,每个主题都可以有任意数量的观察者,抽象主题提供一个接口,可以增加和删除观察者角色
  • ConcreteSubject - 具体主题,也就是具体被观察者(ConcreteObservable)的角色,该角色将有关状态存入具体的观察者对象,在具体主题的内部状态发生改变时,给所有注册过的观察者发出通知
  • Observer - 抽象观察者,观察者的抽象类,定义了一个接口,使得在得到主题的更改通知时更新自己
  • ConcreteObserver - 具体的观察者,该角色实现抽象观察者角色所定义的更新接口,以便在主题的状态改变时更新自己

简单实现

新闻专栏中每天都有新闻更新,但是它的更新消息只有那些订阅了新闻专栏的人才知道,也就是新闻专栏每天都会把新闻发布给订阅用户,这种模式叫做发布---订阅,也就是观察者模式,下面用代码来模拟新闻的发布---订阅过程。

首先要知道的是本例用到的Observer和Observable都是JDK中的内置类型

观察者角色,JDK内置

package java.util;

public interface Observer {
    void update(Observable o, Object arg);
}

订阅者,订阅了新闻的人,即具体观察者角色

public class SubScriber implements Observer {

    private String name;

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

    @Override
    public void update(Observable o, Object arg) {
        System.out.println("你好!" + name + ", 新闻专栏更新啦!" + arg);
    }

    @androidx.annotation.NonNull
    @Override
    public String toString() {
        return "订阅者: " + name;
    }
}

被观察者角色,JDK内置,下面列举了几个主要的方法

public class Observable {
    private boolean changed = false;
    private Vector<Observer> obs;//观察者列表

    public Observable() {
        obs = new Vector<>();
    }

    //注册观察者到观察者列表(即obs)
    public synchronized void addObserver(Observer o) {
        if (o == null)
            throw new NullPointerException();
        if (!obs.contains(o)) {
            obs.addElement(o);
        }
    }

    //通知观察者更新
    public void notifyObservers(Object arg) {
        Object[] arrLocal;
        synchronized (this) {
            if (!hasChanged())//如果内容没有变即标志位为flase,则返回
                return;
            arrLocal = obs.toArray();//否则将obs转换为数组
            clearChanged();//设置标志位为false
        }
        //遍历观察者,通知它们更新
        for (int i = arrLocal.length-1; i>=0; i--)
            ((Observer)arrLocal[i]).update(this, arg);
    }
    
    //设置标志位为true
    protected synchronized void setChanged() {
        changed = true;
    }

    //设置标志位为false
    protected synchronized void clearChanged() {
        changed = false;
    }
    
    //判单标志位
    public synchronized boolean hasChanged() {
        return changed;
    }
}

新闻专栏,即具体的被观察者角色,当它有更新时通知所有观察者(这里是订阅者)

public class NewsColumn extends Observable {

    /**
     * 发布新闻
     * @param content 新闻内容
     */
    public void postNews(String content){
        //设置标志位为true,表示有新内容
        setChanged();
        //通知所有观察者(即订阅了这新闻的人们)
        notifyObservers(content);
    }

}

测试代码

public class Test {

    public static void main(String[] args){
        //新闻专栏(被观察者角色)
        NewsColumn newsColumn = new NewsColumn();
        //订阅者(观察者角色)
        SubScriber subScriber1 = new SubScriber("小宁");
        SubScriber subScriber2 = new SubScriber("小明");
        SubScriber subScriber3 = new SubScriber("李华");
        //订阅者订阅新闻(即将观察者注册到被观察者对象的观察者列表中)
        newsColumn.addObserver(subScriber1);
        newsColumn.addObserver(subScriber2);
        newsColumn.addObserver(subScriber3);
        //发布新闻
        newsColumn.postNews("今天有大事发生!");
    }

}

输出结果

你好!李华, 新闻专栏更新啦!今天有大事发生!
你好!小明, 新闻专栏更新啦!今天有大事发生!
你好!小宁, 新闻专栏更新啦!今天有大事发生!

可以看到,当NewsColumn有新闻发布时,会遍历所有Subscriber,通过调用其updata方法给Subscriber发布新闻,这个过程中,通知系统都是依赖Observer和Observable这些抽象类,NewsColumn和Subscriber完全没有耦合,保证订阅系统的稳定性灵活性。而且Observer和Observable都是JDK中的内置类型,可见观察者模式的重要性。

总结

观察者模式主要作用就是对象解耦,通过将观察者和被观察者完全隔绝,只依赖Observer和Observable这些抽象类。

本文相关源码位置

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值