设计模式之观察者模式

Posted xzj_2013

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式之观察者模式相关的知识,希望对你有一定的参考价值。

1.定义

定义对象之间的一对多依赖关系,当一个对象改变状态是,所有依赖于它的对象都会自动获得通知;

又叫做发布-订阅(publish-subscribe)模式,模型-视图(Model/View)模式,源-监听器(Source、Listener)模式

2.实现原理

  该模式必须包含观察者和被观察对象两种角色。
  观察者和被观察者之间存在“观察”的逻辑关系,当被观察者发生改变的时候,观察者就会观察到这样的变化,发出相应的改变。
  目标类需要:
  1、注册观察者(观察者通知目标:我要当你的观察者)
  2、移除观察者(观察者通知目标:我不再观察你了,你所有的变化都无需通知我了)
  3、如果发生了变化,调用观察者的提供的方法通知观察者
  观察者需要:
  1、提供目标通知观察者时用到的方法
  2、将自己注册成目标的观察者

示意图:

3.角色

  • 抽象被观察者角色:也就是示意图中的Subject,是一个抽象主题,它把所有对观察者对象的引用保存在一个集合中,每个主题都可以有任意数量的观察者。抽象主题提供一个接口,可以增加和删除观察者角色。一般用一个抽象类或者接口来实现。
  • 抽象观察者角色:也就是示意图中的Observer,为所有的具体观察者定义一个接口,在得到主题通知时更新自己。
  • 具体被观察者角色:也就是示意图中的RealSubject,在主题的内部状态改变时,向所有登记过的观察者发出通知。
  • 具体观察者角色:也就是示意图中的RealObserver,实现抽象观察者角色所需要的更新接口,一边使本身的状态与主题的状态相协调。

4.优缺点

   观察者模式的主要的作用就是对对象解耦,将观察者和被观察者完全隔离。
   1、观察者模式的优点
   观察者模式解除了主题和具体观察者的耦合,让耦合的双方都依赖于抽象,而不是依赖具体。
   2、观察者模式的缺点
   在应用观察者模式时需要考虑一下开发小路问题,程序中包括一个被观察者和多个被观察者,开发和调试比较复杂,而且Java中的消息
   的通知默认是顺序执行的,一个观察者的卡顿会影响整体的执行效率。在这种情况下,一般考虑采用异步的方式。

5.注意

需要了解下发布订阅模式和观察者模式之间的区别:
虽然说观察者模式有时也被叫做发布订阅模式,但发布订阅模式其实是在观察者模式上的一种优化;

  观察者模式属于行为型模式,行为型模式关注的是对象之间的通讯,观察者模式就是观察者和被观察者之间的通讯。

  在“发布者-订阅者”模式中,称为发布者的消息发送者不会将消息编程为直接发送给称为订阅者的特定接收者。这意味着发布者和订阅者
  不知道彼此的存在。存在第三个组件,称为代理或消息代理或事件总线,它由发布者和订阅者都知道,它过滤所有传入的消息并相应地
  分发它们。换句话说,pub-sub是用于在不同系统组件之间传递消息的模式,而这些组件不知道关于彼此身份的任何信息

  可以理解为发布订阅模式中统一由调度中心进行处理,订阅者和发布者互不干扰。这样一方面实现了解耦,还有就是可以实现更细粒度的
  一些控制。比如发布者发布了很多消息,但是不想所有的订阅者都接收到,就可以在调度中心做一些处理,类似于权限控制之类的

用一个图来表示两者的区别

 1.在Observer模式中,Observers知道Subject,同时Subject还保留了Observers的记录。然而,在发布者/订阅者中,发布者和订阅者
 不需要彼此了解。他们只是在消息队列或代理的帮助下进行通信。
 2.在Publisher / Subscriber模式中,组件是松散耦合的,而不是Observer模式。
 3.观察者模式主要以同步方式实现,即当某些事件发生时,Subject调用其所有观察者的适当方法。发布者/订阅者在大多情况下是异步方式
(使用消息队列)。
 4.观察者模式需要在单个应用程序地址空间中实现。另一方面,发布者/订阅者模式更像是跨应用程序模式。
    
 尽管这些模式之间存在差异,但有些人可能会说发布者 - 订阅者模式是观察者模式的变体,因为它们之间存在概念上的相似性,但并不是
 一样的

6.代码实例

package com.eric.rxjavademo.observablePatten;

/**
 * 抽象观察者
 */
public interface Observer 

    public void update();



package com.eric.rxjavademo.observablePatten;

/**
 * 抽象的被观察
 */
public interface Subject 

    public void attach(Observer o);

    public void detach(Observer o);

    public void notifyObserver();



package com.eric.rxjavademo.observablePatten;

import java.util.ArrayList;
import java.util.List;

/**
 * 真实的被观察者
 */
public class RealSubject implements Subject 

    private List<Observer> allObservers = new ArrayList<>();

    @Override
    public void attach(Observer o) 
        allObservers.add(o);
    

    @Override
    public void detach(Observer o) 
        allObservers.remove(o);
    

    @Override
    public void notifyObserver() 
        for (Observer o:allObservers)
            o.update();
        
    



package com.eric.rxjavademo.observablePatten;

/**
 * 真实的观察者
 */
public class RealObserver implements Observer 
    @Override
    public void update() 
        System.out.println("我是RealObserver ,我收到了数据");
    


package com.eric.rxjavademo.observablePatten;

/**
 * 真实的观察者B
 */
public class RealObserverB implements Observer 
    @Override
    public void update() 
        System.out.println("我是RealObserverB ,我收到了数据");
    


package com.eric.rxjavademo.observablePatten;

//测试
public class Test 

    public static void main(String[] args)

        Subject subject = new RealSubject();

        Observer observerA = new RealObserver();
        Observer observerB = new RealObserverB();

        subject.attach(observerA);
        subject.attach(observerB);

        subject.notifyObserver();

    



输出
我是RealObserver ,我收到了数据
我是RealObserverB ,我收到了数据

以上是关于设计模式之观察者模式的主要内容,如果未能解决你的问题,请参考以下文章

PHP设计模式之----观察者模式

设计模式系列之四:观察者模式

浅谈javascript之经典设计模式——观察者模式

设计模式之观察者模式

原创设计模式之9:观察者设计模式

设计模式之观察者模式(Observer)