RxJava 之教你写响应式框架(一)

1,477 阅读4分钟

在真正开始编写自己的响应式框架之前,我们先来从观察者模式说起。已经对观察者模式很熟悉的可以直接掠过。

基本概念

观察者模式属于对象行为模式之一,也可叫做发布——订阅模式。它定义了一种以对多的依赖关系,让多个观察者(订阅者)同时观察(监听)一个被观察者(主题),当被观察者的状态发生变化时,会通知所有的观察者对象。

在我们了解什么是观察者模式之后,我们来看一下观察者模式的结构:
这里写图片描述

通过上图我们可以看出观察者涉及到了四种角色:

  • 抽象主题角色(Subject):抽象主题角色保存了所有注册的观察者的引用,同时提供了对观察者的管理,抽象主题角色也叫做被观察者(Observable)
  • 具体主题角色(ConcreteSubject):在具体主题内部状态发生变化时,给所有注册过的观察这发出通知.
  • 抽象观察者角色(Observer):为所有的具体观察者定义的约束接口,在得到主题通知时更新自己.
  • 具体观察者角色(ConcreteObserver):具体观察者实现抽象观察者角色,以便接受主题改变的状态.

代码实现

现在我们来看一下代码的实现

抽象主题角色:

public abstract class Subject {
    private List list = new ArrayList<>();

    
    public void attach(Observer observer) {
        list.add(observer);
    }
    
    public void detach(Observer observer) {
        list.remove(observer);
    }
    
    public void notifyObservers(String newState) {
        list.stream().forEach(ob->{ob.update(newState);});
    }

}

具体主题角色:

public class ConcreteSubject extends Subject {
    public void change(String state) {
        this.notifyObservers(state);
    }
}

抽象观察者

public interface Observer {
    void update(String state);
}

具体观察者

public class ConcreteObserver implements Observer {

    @Override
    public void update(String state) {
        System.out.println("主题状态改变了:" + state);
    }
}

客户端测试类:

public class Client {
    public static void main(String[] args) {
        ConcreteSubject subject = new ConcreteSubject();
        Observer observer = new ConcreteObserver();
        
        subject.attach(observer);
        subject.change("1");

    }
}

到现在为止一个基本的观察者模式已经实现了.

推模型和拉模型

在实际使用中,观察者往往需要更多的有关主题的状态,并且在项目的起始阶段我们通常想不到以后的观察者会需要观察者的什么信息,那该如何解决呢?在解决这个问题之前,我们先来看一下观察者模式的两种模型:

  • 推模型:该模型假设主题对象知道观察者需要的数据,双方提前做好约定,以后需求变动的可能性较小.上面的例子就是典型的推模型:Observer只想知道Subject的状态.
  • 拉模型:主题对象不能确定被观察者到底需要什么信息,因此,直接将自己的引用传给被观察者,被观察者根据自己需求通过主题的引用再去拉去数据.

了解完这两种模型之后,我们已经有了解决上面提出的问题的方案了:采用拉模型来实现。

让我们来看一下拉模型中的代码实现:
抽象主题角色:

public abstract class Subject {
    private List list = new ArrayList<>();

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

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

    public void notifyObservers() {
        list.stream().forEach(ob->{ob.update(this);});
    }

}

具体主题角色:

public class ConcreteSubject extends Subject {
    private String title;
    private String author;

    public String getTitle() {
        return title;
    }

    public String getAuthor() {
        return author;
    }

    public void change(String title, String author) {
        this.title = title;
        this.author = author;
        this.notifyObservers();
    }
}

抽象观察者:

public interface Observer {
    void update(Subject subject);
}

具体观察者:

public class ConcreteObserver implements Observer {

    @Override
    public void update(Subject subject) {
        
        System.out.println(((ConcreteSubject) subject).getAuthor());
        System.out.println(((ConcreteSubject) subject).getTitle());

    }
}

客户端测试:

public class Client {
    public static void main(String[] args) {
        ConcreteSubject subject = new ConcreteSubject();
        Observer observer = new ConcreteObserver();
        subject.attach(observer);

        subject.change("java core", "ms");
    }
}

到现在为止你已经了解了观察者模式,现在让我们来回答一个简单的问题,什么时候需要用观察者模式呢?
首先,我们要强调一点不是为了模式而模式,而是为了解决问题而模式。

观察者模式非常适合于多个对象的变化依赖于某个对象的变化的这种情况。举个例子:上课情况下,所有的学生的都是将注意力放在老师身上,当老师在讲台上移动时(主题状态变化),学生的眼球的移动应该是跟随老师的(观察者根据主题的变化来变化)

到现在为止,你已经有了编写响应式框架的基础。那么在下一篇中,我们将一步一步编写自己的响应式框架。