观察者模式

定义

观察者模式又名发布-订阅模式,定义了对象之间的一对多依赖,多个对象同时监听一个对象,当被监听对象的状态发生改变时,它的所有依赖者都会收到通知并自动更新,被监听对象称为主题suject,监听对象称为观察者observer。

简单来说,observer必须实现update方法,来接收suject状态变化时的通知及更新。suject维护一个observer列表,在状态变化时会逐个的调用observer的update方法来通知、更新observer,为此,suject须提供注册(添加observer到列表)、删除、通知更新三个方法。

  • 观察者模式又分为两种模式:push pull
    1. push是指suject在状态变化时将所有的状态信息都发给observer
    2. pull则是suject通知observer更新时,observer获取自己感兴趣的状态。
  • 两种模式在实现上的区别
    1. push模式下,observer的update方法接收的是状态信息
    2. pull模式下,update方法接收的是suject对象,这种情况下,suject须提供状态信息的get方法,让observer可以获取自己感兴趣的信息。
  • 两种模式的优劣
    push模式要求suject必须了解observer需要的状态,pull则是observer按需获取;push模式下observer的update方法的参数是具体的状态信息,发生变化时必须要重写update方法,pull模式则是将suject对象本身传给update,是最大的参数集合。

push模式实现

  • suject超类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    package observer.push;

    import java.util.LinkedList;
    import java.util.List;

    /**
    * 推模式主题超类,能够注册、删除、数据变动时通知关注者
    * @author sky
    *
    */
    public abstract class Subject {
    /**
    * 观察者名单
    */
    private List<Observer> list = new LinkedList<>();
    /**
    * 注册观察者
    * @param o 观察者
    */
    public void addObserver(Observer o){
    list.add(o);
    }
    /**
    * 删除观察者
    * @param o 观察者
    */
    public void deleteObserver(Observer o){
    int i = list.indexOf(o);
    if (i>-1) {
    list.remove(i);
    }
    }
    /**
    * 通知观察者
    */
    public void notifyObservers(String state){
    for (Observer o:list) {
    o.update(state);
    }
    }
    }
  • observer接口

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    package observer.push;
    /**
    * 推模式观察者接口
    * @author sky
    *
    */
    public interface Observer {

    public void update(String state);

    }
  • suject具体实现类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    package observer.push;

    public class ConcreteSubject extends Subject {
    /**
    * 状态
    */
    public String state;
    /**
    * 状态是否改变的标志
    */
    public boolean isChanged = false;

    /**
    * 状态改变后,通知观察者
    */
    public void change(){
    if (isChanged) {
    this.notifyObservers(state);
    }
    }

    public String getState() {
    return state;
    }

    public void setState(String state) {
    this.state = state;
    isChanged = true;
    }

    public boolean isChanged() {
    return isChanged;
    }

    public void setChanged(boolean isChanged) {
    this.isChanged = isChanged;
    }

    }
  • observ具体实现类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    package observer.push;
    /**
    * 推模式观察者实现类
    * @author sky
    *
    */
    public class ConcreteObserver implements Observer {

    public String name;

    public ConcreteObserver(String n){
    name=n;
    }

    @Override
    public void update(String state) {
    System.out.println(name+" update new state:"+state);

    }

    }
  • 测试类:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    package observer.push;

    public class Test {

    /**
    * @param args
    */
    public static void main(String[] args) {
    ConcreteSubject subject = new ConcreteSubject();
    Observer o1 = new ConcreteObserver("张山");
    Observer o2 = new ConcreteObserver("李四");
    subject.addObserver(o1);
    subject.addObserver(o2);
    System.out.println("准备:");
    subject.setState("上班了");
    subject.change();
    subject.setState("下班了");
    subject.change();
    }

    }
  • 输出

    1
    2
    3
    4
    5
    准备:
    张山 update new state:上班了
    李四 update new state:上班了
    张山 update new state:下班了
    李四 update new state:下班了

pull模式实现

  • suject超类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    package observer.pull;

    import java.util.LinkedList;
    import java.util.List;

    /**
    * 拉模式主题超类,能够注册、删除、数据变动时通知关注者
    * @author sky
    *
    */
    public abstract class Subject {
    /**
    * 观察者名单
    */
    private List<Observer> list = new LinkedList<>();
    /**
    * 注册观察者
    * @param o 观察者
    */
    public void addObserver(Observer o){
    list.add(o);
    }
    /**
    * 删除观察者
    * @param o 观察者
    */
    public void deleteObserver(Observer o){
    int i = list.indexOf(o);
    if (i>-1) {
    list.remove(i);
    }
    }
    /**
    * 通知观察者
    */
    public void notifyObservers(){
    for (Observer o:list) {
    o.update(this);
    }
    }
    }
  • observer接口

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    package observer.pull;
    /**
    * 拉模式观察者接口
    * @author sky
    *
    */
    public interface Observer {

    public void update(Subject s);

    }
  • suject具体实现类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    package observer.pull;

    public class ConcreteSubject extends Subject {
    /**
    * 状态
    */
    public String state;
    /**
    * 状态是否改变的标志
    */
    public boolean isChanged = false;

    /**
    * 状态改变后,通知观察者
    */
    public void change(){
    if (isChanged) {
    this.notifyObservers();
    }
    }

    public String getState() {
    return state;
    }

    public void setState(String state) {
    this.state = state;
    isChanged = true;
    }

    public boolean isChanged() {
    return isChanged;
    }

    public void setChanged(boolean isChanged) {
    this.isChanged = isChanged;
    }

    }
  • observer具体实现类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    package observer.pull;
    /**
    * 拉模式观察者实现类
    * @author sky
    *
    */
    public class ConcreteObserver implements Observer {

    public String name;

    public ConcreteObserver(String n){
    name=n;
    }

    @Override
    public void update(Subject s) {
    String state = ((ConcreteSubject)s).getState();
    System.out.println(name+" update new state:"+state);

    }


    }
  • 测试类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    package observer.pull;

    public class Test {

    /**
    * @param args
    */
    public static void main(String[] args) {
    ConcreteSubject subject = new ConcreteSubject();
    Observer o1 = new ConcreteObserver("张山");
    Observer o2 = new ConcreteObserver("李四");
    subject.addObserver(o1);
    subject.addObserver(o2);
    System.out.println("pull模式准备:");
    subject.setState("上班了");
    subject.change();
    subject.setState("下班了");
    subject.change();
    }

    }
  • 输出

    1
    2
    3
    4
    5
    pull模式准备:
    张山 update new state:上班了
    李四 update new state:上班了
    张山 update new state:下班了
    李四 update new state:下班了