少于 1 分钟阅读

简介

输入只能是一个变量。也可以是一个执行逻辑。而“输入可以是一个执行逻辑”的意义远比我们想象的大。回调只是一种编程模式,允许你在某个操作完成时(无论同步异步)执行某些代码。

回调在编程中的应用

替换模板模式

我们先来用模板模式实现一个功能,下面的B类可以看成是现实中的HibernateTemplate类

public abstract class B{  
    public void execute(){   
        getConnection();    
        doCRUD();    
        releaseConnection();    
	}    
    public abstract void doCRUD();  
    public void getConnection(){    
        System.out.println("获得连接...");    
    }    
    public void releaseConnection(){    
        System.out.println("释放连接...");    
    }    
}  
public class A extends B{  
    public void doCRUD(){    
    	add()
    }    
    public void add(){    
    	...
    }    
}  
public class C extends B{  
    public void doCRUD(){    
    	delete()
    }    
    public void delete(){    
    	...
    }    
}  

用回调的办法实现下

interface CallBack{   
    public void doCRUD();     
}    
class A{
    private B b;
    public void add(){    
       b.execute(new CustomCallBack(){
            public void doCRUD(){    
                System.out.println("执行add操作...");    
            }
       });
    }    
}
public class B{  
    public void execute(CallBack action){ 
        getConnection();    
        action.doCRUD(); 
        releaseConnection();    
    }    
    public void getConnection(){    
        System.out.println("获得连接...");    
    }    
    public void releaseConnection(){    
        System.out.println("释放连接...");    
    }    
} 

可以看到,使用回调后,AB从模板模式中的父子关系,变成了依赖关系。模板模式和回调都可以实现一种效果:在一个完整的过程中预留接口,交给其它类实现。

在分层中的应用

比如netty,一旦一个netty server开始运行,它就是一个完整的运行逻辑,有自己的线程模型。笔者以前做的一个抽象,将message处理代码从handler里抽取出来,自己定义一个messageDispatcher,messageDispatcher根据相关字段分发到不同的processor。其实我可以再进一步,将dispatcher和processor完全抽取出来,封装成一个messagehandler,传给netty server。

这样,netty server就完全可以独立作为一个数据传输层而存在。messagehandler单独作为一个数据协议层。从代码的运行情况看,数据协议层和数据传输层不分家。但从代码的管理角度,它们可以是两个项目,从设计上这样做的优越性就更大了,只要定义好数据协议层和传输层的接口,具体实现可以随意替换。

回调在拆分中的作用

假设原来有一个比较复杂的方法,想将其拆分成两个方法(此场景也适合拆分类)。假设我们要抽出的步骤是不连续的,比如将235抽取成一个函数),那么就要用到回调。(在实际的应用中,会出现“步骤14使用了同样的数据,并且从语义上它们更适合在一起”的情况)

class A{
    void func(){
        1.xx
        2.xx
        3.xx
        4.xx
        5.xx
    }
}

 class A{
    void func(){
        1.xx
        func2(arg,new Callback(){
            void callback(){
                4. xx
            }
        })  
    }
    void func2(arg,callback){
        2. xx
        3. xx
        4. callback()
        5. xx
    }
}

在两个线程间使用callback

map<long,callback> callbackManager
sendThead{
	void send(Message,callback){
		callbackManager.put(message.getId(), callback);
		ioBusiness.send(message);
	}
}
receiveThread{
	void receive(message){
		// 收发的同一个message必须具备相同的id
		callback = callbackManager.get(message.getId());
		callback.run();
	}
}

跟线程间callback差不多,只是需要一个callbackManager来维护映射关系。

回调在架构设计中的应用

http callback

最近一段学习marathon,发现一个有意思的东西。我们可以向marathon发出订阅请求,当发生某个事件时,marathon主动向外界发出http请求,我们写一个http服务监听,即可感知到某个事件的发生。

标签:

分类:

更新时间:

留下评论