Java接口回调

Java接口回调

1. 关于回调

回调机制是一种常见的设计模型,他把工作流内的某个功能,按照约定的接口暴露给外部使用者,为外部使用者提供数据,或要求外部使用者提供数据。

软件模块之间总是存在着一定的接口,从调用方式上,可以把他们分为三类:同步调用、回调和异步调用。

  1. 同步调用:一种阻塞式调用,调用方要等待对方执行完毕才返回,它是一种单向调用。
  2. 异步调用:一种类似消息或事件的机制,不过它的调用方向刚好相反,接口的服务在收到某种讯息或发生某种事件时,会主动通知客户方(即调用客户方的接口)。
  3. 回调:一种双向调用模式,也就是说,被调用方在接口被调用时也会调用对方的接口。

回调和异步调用的关系非常紧密:使用回调来实现异步消息的注册,通过异步调用来实现消息的通知。

2. Java接口回调

Java的接口支持提供了一种获得回调的机制,其技巧就是:定义一个简单接口,并在该接口中声明我们要调用的方法。

下面以一个示例来分析如何使用接口回调。

示例1

假如我们要发射火箭,由专门的人来发射(如专家、领导),如果我们要计算出火箭开始发射时间、发射结束时间及发送成功与否,那么可以使用回调机制来完成。

首先,建立一个接口:

package com.demo;

/**
 * 该接口主要定义可回调的方法
 * 
 * @author 小明
 *
 */
public interface Delegate {

    /**
     * 开始发送时间
     * 
     * @return 开始发送的时间
     */
    long startTime();

    /**
     * 发送结束时间
     * 
     * @return 结束发送的时间
     */
    long endTime();

    /**
     * 发送发射成功与否的消息
     */
    void sendFailedInfo();
}

建立火箭类:

package com.demo;

/**
 * 火箭类,使用到回调接口中的方法
 * 
 * @author 小明
 *
 */
public class Rocket {
    // 火箭将计时的操作委托给受托者处理
    private Delegate delegate;

    public Rocket(Delegate delegate) {
        super();
        this.delegate = delegate;
    }

    /**
     * 获取开始发送时间
     * 
     * @return 开始发送时间
     */
    public long getRocketStartTime() {
        return delegate.startTime();
    }

    /**
     * 获取发送结束时间
     * 
     * @return 结束发送时间
     */
    public long getRocketEndTime() {
        return delegate.endTime();
    }

    /**
     * 判断是否发送成功
     * 
     * @return 是否发送成功
     */
    public boolean isOk() {
        if (getRocketEndTime() - getRocketStartTime() <= 1000)
            return true;
        delegate.sendFailedInfo();
        return false;
    }
}

建立专家类:

package com.demo;

/**
 * 专家类,实现回调接口,作为受托者身份出现
 * 
 * @author 小明
 *
 */
public class ProfessionalWorker implements Delegate {

    @Override
    public long startTime() {
        return System.currentTimeMillis();
    }

    @Override
    public long endTime() {
        return System.currentTimeMillis();
    }

    @Override
    public void sendFailedInfo() {
        System.out.println("嘀...嘀...嘀...发射超时...");
    }

    /**
     * 发射火箭
     */
    public void send() {
        if (new Rocket(this).isOk()){
            System.out.println("发射成功!!!");
        }
    }
}

测试让专家发射火箭:

package com.demo;

public class Test {
    public static void main(String[] args) {
        ProfessionalWorker worker = new ProfessionalWorker();
        worker.send();
    }
}

再比如我们让领导来发射火箭:

package com.demo;

/**
 * 领导
 * 
 * @author 小明
 *
 */
public class Leader {

    /**
     * 发送火箭
     */
    public void send() {
        // 使用匿名内部类实现委托操作
        boolean isOk = new Rocket(new Delegate() {

            @Override
            public long startTime() {
                return System.currentTimeMillis();
            }

            @Override
            public void sendFailedInfo() {
                System.out.println("嘀...嘀...嘀...发射超时...");
            }

            @Override
            public long endTime() {
                return System.currentTimeMillis() + 2000;
            }
        }).isOk();

        if (isOk) {
            System.out.println("发射成功");
        }
    }
}

测试让领导发射火箭:

package com.demo;

public class Test {
    public static void main(String[] args) {
        new Leader().send();
    }
}

示例2

下面再举一个接口回调的例子,假如我们设计一个按钮,当点击这个按钮的时候得到点击操作的通知,我们先建立一个类:

package com.demo2;

/**
 * 事件类
 * 
 * @author 小明
 *
 */
public class Event {

    private String commandText; // 命令文本
    private long when; // 触发时间

    public Event(String commandText) {
        super();
        this.commandText = commandText;
        this.when = System.currentTimeMillis();
    }

    /**
     * 获取命令文本
     * 
     * @return 命令文本字符串
     */
    public String getCommandText() {
        return this.commandText;
    }

    /**
     * 获取事件触发时间
     * 
     * @return 触发时间
     */
    public long getWhen() {
        return when;
    }
}

那么,我们可以定义这样一个接口,用于事件监听:

package com.demo2;

/**
 * 事件监听器接口
 * 
 * @author 小明
 *
 */
public interface Listener {

    /**
     * 监听动作
     * 
     * @param event
     *            事件
     */
    void action(Event event);
}

再定义一个按钮类:

package com.demo2;

/**
 * 按钮类
 * 
 * @author 小明
 *
 */
public class Button {

    private String text; // 按钮文本
    private Listener listener; // 监听器对象

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

    /**
     * 设置事件监听器
     * 
     * @param listener
     *            监听器对象
     */
    public void setEventListener(Listener listener) {
        this.listener = listener;
    }

    /**
     * 点击按钮
     */
    public void press() {
        if (listener != null) { // 事件监听器不为空
            Event event = new Event(this.getText());
            listener.action(event);
        }
    }
}

如果我们要模拟按钮的点击事件,则先实现监听器的接口:

package com.demo2;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 实现事件监听器接口的类
 * 
 * @author 小明
 *
 */
public class MyEventListener implements Listener {

    @Override
    public void action(Event event) {
        System.out.println("命令文本:" + event.getCommandText());
        System.out.println("在" + dateToString(event.getWhen()) + "时,点击了按钮");
    }

    private String dateToString(long time) {
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
                .format(new Date(time));
    }
}

模拟实现点击:

package com.demo2;

/**
 * 测试类
 * 
 * @author 小明
 *
 */
public class Test {
    public static void main(String[] args) {
        /* 创建按钮 */
        Button btn = new Button();
        btn.setText("登录");
        /* 为按钮设置事件监听器 */
        btn.setEventListener(new MyEventListener());
        /* 模拟点击按钮 */
        btn.press();
    }
}

上述示例也是使用接口回调的方式实现的,是在Java Swing中典型的事件驱动机制处理方式。事件驱动机制采用委托方式实现,委托又通过接口回调来完成具体功能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值