zoukankan      html  css  js  c++  java
  • 回调函数

    1 模块间调用

    模块间调用分为三种

    1. 同步调用:A类的方法a()直接调用B类的b()方法。
    2. 异步调用:类A的方法方法a()通过新起线程的方式调用类B的方法b(),代码接着直接往下执行。
    3. 回调:类A在a()中调用类B的b()方法,b()方法中又调用了在类A中定义的方法。

    2 回调

    2.1 其实回调也是一种普通的调用。我们在一个类中定义好行为,而具体什么时候调用,交给另一个类的方法,其实就是传递引用。我们先来看下下面的调用

    public class CallbackTest {
    
        public static void main(String[] args) {
            CallbackTest callbackTest = new CallbackTest();
            callbackTest.test();
        }
    
        public void test() {
            Callback callback = new Callback();
    
            Foo foo = new Foo();
            foo.test(callback); // 将callback引用传入
        }
    }
    
    class Callback { // 普通的类
        public void call(String name) { // 参数具体是什么是调用的时候指定的
            System.out.println("call: " + name); // 声明行为
        }
    }
    
    class Foo { // 普通的类
        public void test(Callback callback) {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            callback.call("hello"); // 具体什么时候执行
        }
    }
    

    在上面的代码中,我们分别有两个普通的类Callback和Foo,Foo的test方法接受一个Callback对象,并调用Callback对象的call方法。这很好理解。

    2.2 我们同样可以写一个Callback的子类,来实现自己的方法。

    public class CallbackTest {
    
        public static void main(String[] args) {
            CallbackTest callbackTest = new CallbackTest();
            callbackTest.test();
        }
    
        public void test() {
            Callback callback = new MyCallback(); // 使用子类覆盖
    
            Foo foo = new Foo();
            foo.test(callback); // 将callback引用传入
        }
    }
    
    class Callback { // 普通的类
        public void call(String name) {
            System.out.println("call: " + name);
        }
    }
    
    class MyCallback extends Callback {
        public void call(String name) {
            System.out.println("my call: " + name); // 声明自己的行为
        }
    }
    
    class Foo { // 普通的类
        public void test(Callback callback) {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            callback.call("hello");
        }
    }
    

    上述代码中Callback更通常的写法应该是写成接口或者抽象类。上述代码还可以有一个变形,就是让public类继承或实现Callback,如

    public class CallbackTest extends Callback{
    
        public static void main(String[] args) {
            CallbackTest callbackTest = new CallbackTest();
            callbackTest.test();
        }
    
        public void test() {
    //        Callback callback = new MyCallback(); 
    
            Foo foo = new Foo();
            foo.test(this); // 将自己传进去
        }
    
        public void call(String name) {
            System.out.println("my call: " + name); // 定义行为
        }
    }
    
    class Callback { // 普通的类
        public void call(String name) {
            System.out.println("call: " + name);
        }
    }
    
    class Foo { // 普通的类
        public void test(Callback callback) {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            callback.call("hello");
        }
    }
    

    2.3 使用匿名类。上述代码可以简化成使用匿名内部类

    public class CallbackTest {
    
        public static void main(String[] args) {
            CallbackTest callbackTest = new CallbackTest();
            callbackTest.test();
        }
    
        public void test() {
    //        Callback callback = new MyCallback(); 
            Foo foo = new Foo();
            foo.test(new Callback() { // 匿名内部类,通常写法Callback是一个接口,不过普通类也可以
                public void call(String name) {
                    System.out.println("my call: " + name);
                }
            }); // 将callback引用传入
        }
    }
    
    class Callback { // 普通的类
        public void call(String name) {
            System.out.println("call: " + name);
        }
    }
    
    class Foo { // 普通的类
        public void test(Callback callback) {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            callback.call("hello");
        }
    }
    

    2.4 匿名内部类可以访问外部类的方法,因此我们可以将具体的实现放到外部类中。

    public class CallbackTest {
    
        public static void main(String[] args) {
            CallbackTest callbackTest = new CallbackTest();
            callbackTest.test();
        }
    
        public void test() {
    //        Callback callback = new MyCallback();
            Foo foo = new Foo();
            foo.test(new Callback() {
                public void call(String name) {
                    myCall(name); // 调用外部类的方法
                }
            }); // 将callback引用传入
        }
        
        // 具体要进行的行为
        public void myCall(String name) {
            System.out.println("my call: " + name);
        }
    }
    
    class Callback { // 普通的类
        public void call(String name) {
            System.out.println("call: " + name);
        }
    }
    
    class Foo { // 普通的类
        public void test(Callback callback) {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            callback.call("hello");
        }
    }
    

    2.5 回调函数可以加上状态。上面的Callback都是无状态的,我们可以给Callbakc加上状态,然后再调用的时候设置Callback状态,这样通过Callback的引用就可以执行任务执行的状态,类似java中的Future。

    public class CallbackTest {
    
        public static void main(String[] args) {
            CallbackTest callbackTest = new CallbackTest();
            callbackTest.test();
        }
    
        public void test() {
            Callback callback = new MyCallback(); // 使用子类覆盖
    
            Foo foo = new Foo();
            foo.test(callback); // 将callback引用传入
    
            while (!callback.complete) { // 通过callback的引用可以知道调用的状态,是不是项java中的Future?
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("not complete");
            }
            System.out.println("complete");
        }
    }
    
    class Callback { // 普通的类
        public boolean complete = false; // 包含状态
        public void call(String name) {
            System.out.println("call: " + name);
        }
    }
    
    class MyCallback extends Callback {
        public void call(String name) {
            System.out.println("my call: " + name); // 声明自己的行为
        }
    }
    
    class Foo { // 普通的类
        public void test(Callback callback) {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            callback.call("hello");
            callback.complete = true;
        }
    }
    

    总结

    其实回调也是普通的调用,本质同一个引用,被不同的类调用。回调通常和匿名内部类一起来用使得看起来有些复杂,如果能拆开来看的话就会好理解。回调的作用可以理解为将动作和动作开始的时间分离:在自己的类中只定义应该怎么做,然后把这个类的引用给另一个类的方法去调用。

  • 相关阅读:
    设计模式--17、建造者模式
    设计模式--16、原型模式
    面向对象的几大设计原则
    设计模式--15、模板方法模式
    设计模式--14、中介者模式
    设计模式--13、享元模式
    设计模式--12、外观模式
    设计模式--11、命令模式
    消息中间件ActiveMQ、RabbitMQ、RocketMQ、ZeroMQ、Kafka如何选型?
    Kafka,Mq,Redis作为消息队列有何差异?
  • 原文地址:https://www.cnblogs.com/set-cookie/p/8996951.html
Copyright © 2011-2022 走看看