前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java 回调函数的使用

Java 回调函数的使用

作者头像
一灰灰blog
发布2018-02-06 12:10:44
2.6K0
发布2018-02-06 12:10:44
举报
文章被收录于专栏:小灰灰小灰灰

回调函数

回调函数是什么鬼, 回调函数干嘛用,回调函数可以怎么用

如果有过android开发经验,经常可以看到一些类似下面的代码

代码语言:javascript
复制
Button Btn1 = (Button)findViewById(R.id.button1);//获取按钮资源    
Btn1.setOnClickListener(new Button.OnClickListener(){//创建监听    
    public void onClick(View v) {    
        String strTmp = "点击Button01";    
        Ev1.setText(strTmp);    
    }    

});   

上面注册的监听器其实就包含了这个回调的意味了。

软件模块之间总是存在着一定的接口,从调用方式上,可以把他们分为三类:同步调用、回调和异步调用。 同步调用:一种阻塞式调用,调用方要等待对方执行完毕才返回,它是一种单向调用; 回调:一种双向调用模式,也就是说,被调用方在接口被调用时也会调用对方的接口; 异步调用:一种类似消息或事件的机制,不过它的调用方向刚好相反,接口的服务在收到某种讯息或发生某种事件时,会主动通知客户方(即调用客户方的接口)。

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

所谓回调,就是客户程序CLIENT调用服务程序SERVER中的某个函数SA(),然后SERVER又在某个时候反过来调用CLIENT中的某个函数mycallback(),对于CLIENT来说,这个mycallback便叫做回调函数。例如Win32下的窗口过程函数就是一个典型的回调函数。

简单来说,就是在调用一个组建的方法时,按照他的定义,注册一个我们自己的方法,期待这个组建在某一个特地场景下调用我们注册的方法,实现对应的功能

设计回调函数的思路

上面简单的说明了什么是回调函数,那么怎么去设计一个回调函数呢?

首先可以明确的是调用方要实现一个注册方法,被调用方提供一个功能,在某些特定的情况下,会调用注册方法

如一个应用场景是:

如查询一条微博的点赞数,在db中保存了用户+微博的点赞映射关系,通常需要获取点赞数的时候,需要在db中count一下,计算点赞数,当点赞数很多的时候,改怎么办?每次都count一把? 性能开销难以接受

一个简单的方法是使用缓存,将点赞数保存在缓存中,每次获取点赞数都从缓存取,缓存没有命中的时候,才从db中count一把,并回写到缓存中

上面这个应用场景该如何设计成回调函数的形式呢?

  1. 一个缓存客户端,负责从缓存中获取数据 CacheClient
  2. 业务方,对外提供查询点赞数的功能 (一个对外的getCount()接口,一个内部的查询db计算总数的接口)

一般为了通用性而言,CacheClient内部如果将缓存未命中查db的功能代码封装起来,会有什么问题?耦合太高,没法复用

so 形式话的结构如下:

CacheClient:

  1. 回调接口 CallableInterface
  2. 缓存操作类
  3. 注册回调函数类

使用方 CountService:

  1. db中查询评价总数的方法(不然缓存中的初始数据从哪里来?)
  2. 具体的业务使用逻辑代码

实例

看上面的描述能看懂么?卧槽,自己写的东西自己都看不大懂啊,果然还是代码是王道,先看看代码,看一下是怎么玩的,然后在回过头去看一下上面的,效果会好很多

注册器相关类:

回调接口 CacheCallBackInterface

代码语言:javascript
复制
package com.mushroom.hui.common.register.callback;

/**
 * 缓存未命中的回调函数
 * Created by yihui on 16/4/5.
 */
public interface CacheCallBackInterface {

    String getKey(int id);

    int getExpire();

    Object getObject(String key);
}

注册接口 BaseRegister.java --> 为什么要设计成接口?看CacheCient的时候会理解一点的

代码语言:javascript
复制
package com.mushroom.hui.common.register;


import com.mushroom.hui.common.register.callback.CacheCallBackInterface;

import java.util.HashMap;
import java.util.Map;

/**
 * Created by yihui on 16/4/5.
 */
public interface BaseRegister {
    Map<String, CacheCallBackInterface> map = new HashMap<>();

    void register(String name, CacheCallBackInterface callback) throws Exception;

    Object exec(String name, int id) throws Exception;

    <T> T exec(String name, int id, Class<T> clz) throws Exception;
}

CacheClient.java 对外提供的缓存客户端, 这个里面就实现了传说中的回调函数的使用

代码语言:javascript
复制
package com.mushroom.hui.common.cache;

import com.mushroom.hui.common.cache.api.CacheInterface;
import com.mushroom.hui.common.register.BaseRegister;
import com.mushroom.hui.common.register.callback.CacheCallBackInterface;
import com.mushroom.hui.common.register.exception.RegisterException;
import org.apache.commons.lang.StringUtils;

import javax.annotation.Resource;

/**
 * Created by yihui on 16/4/5.
 */
public class CacheClient implements BaseRegister {

    private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(CacheClient.class);

    @Resource(name = "cacheService")
    private CacheInterface methodCache;


    @Override
    public void register(String name, CacheCallBackInterface callback) throws Exception {
        if(StringUtils.isBlank(name)) {
            throw new IllegalArgumentException("key is empty!");
        }

        if (map.containsKey(name)) {
            throw new RegisterException("this callback interface has already registered! name : " + name);
        }

        map.put(name, callback);
    }


    @Override
    public Object exec(String name, int id) throws Exception {
        return exec(name, id, Object.class);
    }


    @Override
    public <T> T exec(String name, int id, Class<T> clz) throws Exception {
        CacheCallBackInterface callBackInterface = map.get(name);
        if (callBackInterface == null) {
            throw new RegisterException("this callback interface has already registered! name : " + name);
        }

        String key = callBackInterface.getKey(id);
        Object obj = methodCache.getObject(key, clz);
        if (obj == null) {
            obj = callBackInterface.getObject(key);
            methodCache.setObject(key, obj, callBackInterface.getExpire());
        }

        return (T) obj;
    }


    /**
     * 获取缓存的对象
     * @param name  注册的回调函数name
     * @param id    id
     * @param clz   返回的对象类型
     * @param <T>
     * @return
     * @throws Exception
     */
    public <T> T getObject(String name, int id, Class<T> clz) throws Exception {
        return exec(name, id, clz);
    }

}

测试类中,对上面的功能进行测试,代码如下:

代码语言:javascript
复制
@Test
public void testCacheClient() throws Exception {
    int id = 1002;
    String name = "cache_test";

    // 注册回调函数
    cacheClient.register(name, new CacheCallBackInterface(){

        @Override
        public String getKey(int id) {
            return "test_" + id;
        }

        @Override
        public int getExpire() {
            return 30;
        }

        @Override
        public Object getObject(String key) {
            return key.length();
        }
    });

    Integer count = cacheClient.getObject(name, id ,Integer.class);
    logger.info("The count is : {}", count);


    cacheService.setObject("test_" + id, 1231234, 30);


    count = cacheClient.getObject(name, id, Integer.class);
    logger.info("The count is : {}", count);


    Thread.sleep(1000);
    count = cacheClient.getObject(name, id, Integer.class);
    logger.info("The count is : {}", count);
}

题外话

写代码的时候还是很清晰,知道应该怎么玩,而实际动手写这个流程的时候,还是有很多问题啊,有一些地方居然不清楚为什么要那么设计,为什么要那么玩,简直了,看来这一块了解的还是不够透彻,后面把这一块吃透后,得重写一遍

最后给出代码的git地址 : https://github.com/liuyueyi/java-web-archetype/tree/demo

(这个工程主要是一个简单的java web demo实例工程,会逐渐的向其中添加一些公用的组件(工作中get到什么,就往里面塞什么东西))

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 回调函数
  • 设计回调函数的思路
  • 实例
  • 题外话
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档