NO.22 举一反三:回调与观察者模式

默然回首,那人却在灯火阑珊处 - 回调模式

Java线程技术是现实世界的复杂业务场景中的“座上宾”。创建线程的方式我们几乎也是烂熟于心:

  1. 继承Thread方式;
  2. 实现Runnable接口方式;
  3. 线程池方式。

代码1:

public class TestThread {
    public static void main(String[] args) {
        Thread t = new Thread(new Runnable(){
            @Override
            public void run() {
            System.out.println("我是run()函数");
            }
        });
        t.start();
    }
}

下面我们继续“折腾”一下,来个不熟悉的版本,实现了同样的功能,如代码2、代码3。

代码2:

//App实现类
public class App implements Runnable {
    //Runnable就是回调接口
    //run就是回调函数
    @Override
    public void run() {
        System.out.println("这里是回调函数");
    }

    //App的执行函数
    public void doRun(Thread t){
        t.start();
    }
}

代码3:

public class TestCallback {
    public static void main(String[] args){
        //定义App对象引用
        App app = new App();
        //定义框架对象引用
        Thread t = new Thread(app);
        //由App函数调用,并传入底层框架对象引用
        app.doRun(t);
    }
}

看了上述代码,是不是觉得也是很熟悉?
是的!读到这里,很多老铁肯定会联想到上篇文章中提到的回调特征图,我们同样放在了本文的图1。Runnable接口是JDK框架定义的回调接口类;Thread类是JDK框架类库提供的类;App类是用户自定义的类;run方法就是回调函数。完全符合回调机制的特征。

是的!老铁们没有想错,我们常用的Runnable接口创建线程的方式,其实就是利用了回调技术。回调技术不仅用于框架实现,在我们很多业务场景中也会用到,请继续往下看。

图1

【注意】文中提及框架/类库只是为了形象化说明是底层实现;同样地,App也只是为了形象划说明是上层实现。回调技术不仅仅用于框架设计中,其本质上是分层思想,同样适用于我们业务代码的实现。

敌不动我不动 - 观察者模式

定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使他们能够自动更新自己 —— 观察者模式定义。

后续会有系列文章讲讲常见设计模式的目的、使用场景、实现技术及优缺点介绍,敬请期待!本文的重点主要讲讲观察者模式的实现方式,show me the code —— 见代码4 - 8 。设计模式的类图很简单,见下图。

代码4:

//观察者;实为“定义回调接口”
public interface Observer {
    //更新方法;实为“定义回调方法”
    public void update();
}

代码5:

//具体观察者
public class ConcreteObserver implements Observer{
    //实现更新方法
    @Override
    public void update() {
        System.out.println("我是回调函数!");
    }
}

代码6:

import java.util.Vector;

//定义被观察者
public abstract class Subject {
    //定义观察者列表
    private Vector<Observer> obses = new Vector<Observer>();

    //注册观察者:实为“注册回调接口”
    public void addObserver(Observer o){
        this.obses.add(o);
    }

    //删除观察者
    public void removeObserver(Observer o){
        this.obses.remove(o);
    }

    //通知注册的所有观察者:实为“调用回调接口”
    public void notifyObservers(){
        for(Observer o : obses){
            //调用更新方法:实为“调用回调”
            o.update();
        }
    }
}

代码7:

//具备的被观察者
public class ConcreteSubject extends Subject{
    //被观察者的自定义动作
    public void userAction(){
        super.notifyObservers();
    }
}

代码8:

public class TestCase {
    public static void main(String[] args){
        //创建一个被观察者
        ConcreteSubject subject = new ConcreteSubject();
        //创建一个观察者
        Observer obs = new ConcreteObserver();
        //将观察者加入到被观察者中
        subject.addObserver(obs);
        //被观察者发起动作
        subject.userAction();
    }
}

老铁们可以自行套用线程例子的方法并结合上述代码中的注释,来识别一下为什么观察者模式也应用了回调技术,并欢迎老铁将思考过程写在留言区与大家共同交流讨论。

更加准确的说法是:观察者模式是“变异”的回调技术。观察者模式中里面被观察者维护了很多的观察者的引用,而回调里面只是维护了一个引用。

划重点

  1. 回调技术是非常常用且实用的技术,平时在看代码、写代码的时候应结合场景需求恰当利用。
  2. 回调技术的应用场景包括:关联行为场景;事件多级触发;消息队列处理等等。

转载自公众号:代码荣耀
图2

猜你喜欢

转载自blog.csdn.net/maijia0754/article/details/80598869