观察者模式学习笔记

121 阅读4分钟

观察者模式

观察者模式属于行为型模式

定义:

首先来了解一下观察者模式的定义:

观察者模式又被称为发布-订阅(Publish/Subscribe)模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己。

角色组成:

观察者模式一共有四个角色:

Subject:抽象主题(抽象被观察者),可翻译为主题或抽象通知者,一般用一个抽象类或者一个接口实现。它把所有对观察者对象的引用保存在一个聚集里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。

Observer:抽象观察者,为所有的具体观察者定义一个接口,在得到主题的通知是更新自己。这个接口叫做更新接口。抽象观察者一般用一个抽象类或者一个接口实现。更新接口通常包含一个update()方法,也就是更新方法。

ConcreteSubject:具体主题(具体被观察者),该角色将有关状态存入具体观察者对象,在具体主题的内部状态发生改变时,给所有注册过的观察者发送通知。具体主题角色通常用一个具体子类实现。

ConcrereObserver:具体观察者,实现抽象观察者定义的更新接口,以便在得到主题更改通知时更新自身的状态。具体观察者角色可以保存一个指向具体主题对象的引用。具体观察者角色通常用一个具体子类实现。

类图:

image.png

案例实现:

在使用微信公众号时,大家都会有这样的体验,当你关注的公众号中有新内容更新的话,它就会推送给

关注公众号的微信用户端。我们使用观察者模式来模拟这样的场景,微信用户就是观察者,微信公众号

是被观察者,有多个的微信用户关注了 一个程序员的成长 这个公众号。

代码如下:

定义抽象观察者类,里面定义一个更新的方法

public interface Observer { 
    /**
     * 更新方法
     *
     * @param message 通知信息
     */
    void update(String message);
}

定义具体观察者类,微信用户是观察者,里面实现了更新的方法,这里用一个输出语句代替具体方法逻辑。

public class WeixinUser implements Observer { 
  // 微信用户名 
  private String nickName; 
  public WeixinUser(String nickName) { 
    this.nickName = nickName; 
  }
  @Override 
  public void update(String message) { 
    System.out.println(nickName + " 收到通知 :   " + message); 
  } 
}

定义抽象主题类,提供了attach、detach、notify三个方法

public interface Subject { 
    /**
     * 添加订阅者(添加观察者对象)
     *
     * @param observer 订阅者对象
     */
    void attach(Observer observer);

    /**
     * 删除订阅者
     *
     * @param observer 订阅者对象
     */
    void detach(Observer observer);

    /**
     * 通知订阅者更新消息
     *
     * @param message 更新消息
     */
    void notify(String message);
}

微信公众号是具体主题(具体被观察者),里面存储了订阅该公众号的微信用户,并实现了抽象主题中的方法

public class SubscriptionSubject implements Subject {

    /**
     * 定义一个集合,用来存储多个观察者对象
     */
    private List<Observer> weiXinUserList = new ArrayList<Observer>();

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

    public void detach(Observer observer) {
        weiXinUserList.remove(observer);
    }

    public void notify(String message) {
        //遍历集合
        for (Observer observer : weiXinUserList) {
            //调用观察者对象中的update方法
            observer.update(message);
        }
    }
}

测试类

public class Test {
    public static void main(String[] args) {
        //1创建公众号对象
        SubscriptionSubject subject = new SubscriptionSubject();

        //2添加用户订阅公众号
        subject.attach(new WeiXinUser("candou"));
        subject.attach(new WeiXinUser("maiya"));
        subject.attach(new WeiXinUser("bingfeng"));

        //3公众号更新,发出消息给订阅者
        subject.notify("一个程序员的成长 公众号更新了");
    }
}

输出结果:

candou 收到通知 :   一个程序员的成长 公众号更新了
maiya 收到通知 :   一个程序员的成长 公众号更新了
bingfeng 收到通知 :   一个程序员的成长 公众号更新了

优缺点:

优点:

降低了目标与观察者之间的耦合关系,两者之间是抽象耦合关系,从而使得各自的变化都不会影响另一边的变化。

被观察者发送通知,所有注册的观察者都会收到信息【可以实现广播机制】

缺点:

如果观察者非常多的话,那么所有的观察者收到被观察者发送的通知,尤其是涉及到数据库的操作时会比较耗时,

如果被观察者有循环依赖的话,那么被观察者发送通知会使观察者循环调用,会导致系统崩溃

使用场景

当一个对象的改变需要同时改变其他对象,而且它不知道具体有多少对象有待改变时,应考虑使用观察者模式。