观察者模式(设计模式)

2019-09-11 09:49:54 浏览数 (2)

概述

观察者模式其实就是发布订阅模式,发布者发布信息,订阅者获取信息,订阅了就能收到信息,没订阅就收不到信息。可以想象成消息中间件在系统中的作用。SpringBoot启动就是使用了观察者模式。

正文

概念:对象间的一对多的依赖关系。网上这个概念说的太宽泛了,请看图:

图1图1

 还有一个图,也可以帮助大家理解

图2图2

首先,观察者是一种面向接口编程,包含的角色有:

Subject(目标):目标又称为主题,它是指被观察的对象。在目标中定义了一个观察者集合,一个观察目标可以接受任意数量的观察者来观察,它提供一系列方法来增加和删除观察者对象,同时它定义了通知方法notify()。目标类可以是接口,也可以是抽象类或具体类。 

ConcreteSubject(具体目标):具体目标是目标类的子类,通常它包含有经常发生改变的数据,当它的状态发生改变时,向它的各个观察者发出通知;同时它还实现了在目标类中定义的抽象业务逻辑方法(如果有的话)。如果无须扩展目标类,则具体目标类可以省略。 

Observer(观察者):观察者将对观察目标的改变做出反应,观察者一般定义为接口,该接口声明了更新数据的方法collect(),因此又称为抽象观察者。 

ConcreteObserver(具体观察者):在具体观察者中维护一个指向具体目标对象的引用,它存储具体观察者的有关状态,这些状态需要和具体目标的状态保持一致;它实现了在抽象观察者Observer中定义的collect()方法。

一共四个类,两个接口,两个接口实现类,被观察者方法参数引用的是观察者对象。

观察者只定义一个自己的行为。具体观察者重写观察者的行为后还提供了构造方法为客户端调用。具体被观察者,这个类有些复杂,简单的说就是把外界消息通过该类的方法调用 notifyObserver() 方法给提前准备好的Observer (观察者) 接口中的方法去发送。

UML图

图 3图 3

观察者模式代码

Subject(被观察者)

代码语言:txt复制
public interface Subject {
    //添加观察者
    void addObserver(Observer o);
    //移除观察者
    void removeObserver(Observer o);
    //通知观察者方法
    void notifyObserver();
}

Observe(观察者)

代码语言:txt复制
public interface Observer {
    //观察者有只有收信息的行为
    void collect(String message);
}

具体观察者

代码语言:txt复制
public class User implements Observer {
 
    private String name;
    private String message;
 
    public User(String name) {
        this.name = name;
    }
 
    public void collect(String message) {
        this.message = message;
        read();
    }
 
    //观察者的实际行为
    public void read() {
        System.out.println(name   " 收到推送消息: "   message);
    }
}

具体被观察者

代码语言:txt复制
//被观察者的实现类,也就是微信公众号服务
public class WeChatServer implements Subject {
    //注意到这个List集合的泛型参数为Observer接口,设计原则:面向接口编程而不是面向实现编程
    private List<Observer> list = new ArrayList<Observer>();
    private String message;
 
    public void addObserver(Observer o) {
        list.add(o);
    }
 
    public void removeObserver(Observer o) {
        if (!list.isEmpty())
            list.remove(o);
    }
 
    //把消息发给每一个订阅的观察者
    public void notifyObserver() {
        for (int i = 0; i < list.size(); i  ) {
            Observer observer = list.get(i);
            observer.collect(message);
        }
    }
 
    public void setInformation(String s) {
        this.message = s;
        System.out.println("微信服务更新消息: "   s);
        //消息更新,通知所有观察者
        notifyObserver();
    }
}

测试主函数

代码语言:txt复制
public class ObserverTest {
    public static void main(String[] args) {
        WeChatServer server = new WeChatServer();
 
        Observer userA = new User("a");
        Observer userB = new User("b");
        Observer userC = new User("c");
        server.addObserver(userA);
        server.addObserver(userB);
        server.addObserver(userC);
        server.setInformation("PHP是世界上最好用的语言!");
 
        System.out.println("----------------------------------------------");
        server.removeObserver(userA);
        server.setInformation("放屁,JAVA是世界上最好用的语言!");
    }
}

输出结果

图 4图 4

总结

在以下情况下可以考虑使用观察者模式: 

(1) 一个抽象模型有两个方面,其中一个方面依赖于另一个方面,将这两个方面封装在独立的对象中使它们可以各自独立地改变和复用。 

(2) 一个对象的改变将导致一个或多个其他对象也发生改变,而并不知道具体有多少对象将发生改变,也不知道这些对象是谁。 

(3) 需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象……,可以使用观察者模式创建一种链式触发机制。

如有订阅性质的,发布性质的都可以使用观察者模式。

0 人点赞