回调-> 观察者模式->反应堆模式
关于回调:
回调是观察者模式以及反应堆模式的基础
一句话,回调就是一种双向调用模式,什么意思呢,就是说,被调用方在被调用时也会调用对方,这就叫回调。“If you call me, i will call back”。
先看看这个可以说比较经典的使用回调的方式:
背景1:class A 实现接口inA
背景2:class A 中包含一个对于class B的引用b
背景3:class B有一个参数为InA的方法test(InA a)
class A的对象a调用B的方法传入自己(由于形参是个inA a),test(a) ——这一步相当于you call me.
然后b就可以在test方法中调用InA的方法(已经将形参:接口a的引用传入了) ——这一步相当于I call you back.
可以参考下面的代码:
//最基本的回调模式实现: public interface inA { public void callBacka(); } public class A implements inA{ //含有个B的实例 B b=new B(); @Override public void callBacka() { // TODO Auto-generated method stub System.out.println("excute the method in class A"); } } public class B { public void test(inA a){ a.callBacka(); } public void excuteB(){ System.out.println("excute the method in class B"); } }
可以看出来,A类可以通过a.b获得b的实例来调用b中的方法,执行完之后,在B类的对应方法中,可以通过传入的A的参数,来实现对于A的方法的回调,这个是很关键的。
回调还可以实现异步操作,比如说,你有一个复杂的问题解决不了,打电话给你的同学,你的同学说可以解决这个问题,但是需要一些时间,那么你不可能一直拿着电话在那里等,你会把你的电话号码告诉他,让他解决之后打电话通知你。回调就是体现在你的同学又反过来拨打你的号码。
结合到前面所分析的,你打电话给你同学就是【you call me】,你同学解决完之后打电话给你就是回调【i call you back】。
两个关键点:
1、A类中包含一个B的引用,作为其属性
2、B类的需要回去到A的方法中,包含一个方法,这个方法的形参是对于A类的引用。
3、回调方法需要用接口实现,这样A可以通过集成接口,实现不同类型的回调方式。
再总结一下:软件模块之间总是存在着一定的接口,从调用方式上,可以把他们分为三类:同步调用、回调和异步调用。同步调用是一种阻塞式调用,调用方要等待对方执行完毕才返回,它是一种单向调用;回调是一种双向调用模式,也就是说,被调用方在接口被调用时也会调用对方的接口;异步调用是一种类似消息或事件的机制,不过它的调用方向刚好相反(注意这个是与之前的的例子相反的),接口的服务在收到某种讯息或发生某种事件时,会主动通知客户方(即调用客户方的接口)。回调和异步调用的关系非常紧密,通常我们使用回调来实现异步消息的注册,通过异步调用来实现消息的通知。(貌似仅仅是用途不同而已 实质上差不多)同步调用是三者当中最简单的,而回调又常常是异步调用的基础。
观察者模式(Observer)
观察者模相当于是回调模式的扩充。在观察者模式中,观察者相当于上面例子中的A,被观察者相当于上面例子中的B。不同的是有多个观察者,一个被观察者,也可以是多个。
观察者模式的官方定义:
观察者模式定义了对象间的一种一对多依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。
当一个被观察者的状态发生改变 所有依赖它的对象都发生变化。
该模式的几个角色:
Subject(被观察的对象接口 ),规定ConcreteSubject的统一接口。
每个Subject可以有多个Observer,(通过在具体实现类中添加观察者引用的ArrayList或者其他类似方式来实现,这是实现回调方式的关键),观察者是先于被观察者创建的,并且要将对于观察者的引用加入到被观察者的ArrayList中,这样才能在被观察者的信息改变了之后通知对应的观察者。(因为观察者是先于被观察者而创建的 而最后要通过被观察者来调用观察者,进行信息的更新,即后创建的,反过来调用先创建的对象,所以是回调)
ConcreteSubject(具体被观察对象)
维护对所有具体观察者的引用的列表,状态发生变化时会发送通知给所有注册的观察者。(通过列表中对于obversor的引用,来是实现回调,更新观察者)
从功能上来讲,ConcreteSubjec至少要包含 addobservor(添加一个观察者) deletobservor(删除一个观察者) 以及updateobservor三个部分,通过updateobservoer来进行回调,对观察者进行更新,或者是通知观察者来执行相对应的事务。
Observer(观察者接口)
规定ConcreteObserver的统一接口;
定义了一个update()方法,在被观察对象状态改变时会被调用。
ConcreteObserver(具体观察者)
维护一个对ConcreteSubject的引用,(这个可以通过对于ConcreteSubject进行引用,以此来调用ConcreteSubject中的方法,比如添加删除之类的操作,这样的话,不用在main函数中生成ConcreteSubject的具体的类了,每一个observer都含有add delete的方法)
特定状态与ConcreteSubject同步,实现Observer接口,通过update()方法接收ConcreteSubject的通知。(回调过来的具体执行部分)
具体分析见下面的代码,将obversor写成了witcher。
//定义观察者接口
public interface iWatcher { public void update(String str); }
//定义被观察者接口
public interface iSubject { public void add(iWatcher w); public void delete(iWatcher w);
//修改观察者类中的信息
public void update(String str); } public class concreteWatcher implements iWatcher { private String str;
private int id; public void setId(int id)
{
this.id=id; }
public int getId(){
return id;
} //构造函数
public concreteWatcher(String str,int id){
this.str=str;
this.id=id;
System.out.println("the str is created:"+str+this.getClass().hashCode());
} @Override
public void update(String str) {
// TODO Auto-generated method stub
this.str=str;
System.out.println(this.getId()+" the str is updated:"+str);
} } public class concreteSubject implements iSubject{ //含有一个观察者的队列 list是观察者队列的引用
ArrayList<iWatcher>list=new ArrayList<iWatcher>();
@Override
public void add(iWatcher w) {
// TODO Auto-generated method stub
list.add(w);
} @Override
public void delete(iWatcher w) {
// TODO Auto-generated method stub
list.remove(w);
} //体现回调的是在这个地方
@Override
public void update(String str) {
// TODO Auto-generated method stub
//由于List是自身类的属性 不用通过方法在去传了
//这里是一个回调 watcher中的方法去进行更新
for(iWatcher w :list){
w.update(str);
}
} } package com.designpatten.Observer; public class Test {
//生成三个观察者
public static void main(String []args){ concreteWatcher a1=new concreteWatcher("watcher1",1);
concreteWatcher a2=new concreteWatcher("watcher2",2);
concreteWatcher a3=new concreteWatcher("watcher3",3); //生成一个被观者 即抽象主题
concreteSubject sub=new concreteSubject();
sub.add(a1);
sub.add(a2);
sub.add(a3); sub.update("update the information"); } }
//执行结果
/*
the str is created:watcher11580958233
the str is created:watcher21580958233
the str is created:watcher31580958233
1 the str is updated:update the information
2 the str is updated:update the information
3 the str is updated:update the information
*/
关于反应堆模式(reactor)
反应器模式(Reactor pattern)与观察者模式(Observer pattern)在这个方面极为相似:当一个主体发生改变时,所有依属体都得到通知。不过,观察者模式与单个事件源关联,而反应器模式则与多个事件源关联 。
Reactor Pattern 是一种为处理服务请求并发提交到一个或者多个服务处理程序的事件设计模式,当请求抵达后,服务处理程序使用多路分配策略,然后同步地派发这些请求至相关的请求处理程序。
Observer patten只是监听一个固定的主题,在reactor patten中,相当于subject的实现实例中同时包含了不同的Aarrylist每个对应一个事件,每一个事件被触发,传到subject中,相对应的Arraylist中引用的类就会被更新(所谓的进行注册过的事件)
在reactor模式中,资料中常常会提到一个Hook Method 即是钩子方法,这个是模板模式的一部分内容,具体的可以参考一下后面列出的链接。
这里就是简单总结一下:
从模板模式的角度来看,方法被分成三类:具体方法,抽象方法,钩子方法。
1、具体方法就是我们平时所写的最常见的最普通的方法。
2、抽象方法在java中就是abstract方法,就是所谓的继承,这个也比较常见。在一个执行过程中几个函数的出现顺序一致,但是每个步骤于在子类中可能有不同的实现,就直接继承,迪对不同的抽象类进行不同的实现即可,这个的核心思想是在父类中提供了一个算法的框架,子类只能遵从这个框架来,但是具体每个步骤的实现上可能有差别。最典型的就是sort函数,每次排序时,可以自定义排序规则,这个可能会设计到具体不同的领域,但是sort函数的整个实现的大的步骤,则是完全固定的。
3、钩子方法其实就是反过来了,利用钩子方法,子类可以一定程度上影响父类的执行流程,钩子方法的返回结果通常为bool型变量,常常将父类中(模板方法)的某一个步骤放在if语句中,如果钩子方法返回true则执行,返回false则不执行。在子类中可以根据实际情况对钩子方法进行覆盖,并对其默认返回值进行修改,从而确定合适的模板方法的执行流程,相当于是子类影响了父类(模板方法)的执行流程。
相关参考资料:
http://blog.csdn.net/pi9nc/article/details/23169357 ( 这个感觉比较通俗 )
http://1025250620.iteye.com/blog/1378538
http://daimojingdeyu.iteye.com/blog/828696
http://blog.csdn.net/fengxinze/article/details/7319059(这个是翻译版本)
(肯定是logserver对象先要生成 才能注册到initial dispatcher中 才能进行回调 说实话 对于例子中的get_handler 看得还是有点晕晕乎乎 先记录在这里)
模板方法模式
http://blog.csdn.net/lenotang/article/details/2911246
http://blog.csdn.net/lovelion/article/details/8299927
其他各种网络资料
回调-> 观察者模式->反应堆模式的更多相关文章
- 反应堆模式(reactor)
在提到高性能服务器编程的时候肯定有听过reactor模式,如果只是简单的写一个服务器和客户端建立连接的程序来熟悉一下使用socket函数编程,一般这种情况都是同步方式实现的,服务器阻塞等待客户端的连接 ...
- 理解Redis的反应堆模式
1. Redis的网络模型 Redis基于Reactor模式(反应堆模式)开发了自己的网络模型,形成了一个完备的基于IO复用的事件驱动服务器,但是不由得浮现几个问题: 为什么要使用Reactor模式呢 ...
- 反应堆模式最牛的那篇论文--由solidmango执笔翻译
The Reactor:An Object-Oriented Wrapper for Event-Driven Port Monitoring and Service Demultiplexing 反 ...
- JAVA设计模式—观察者模式和Reactor反应堆模式
被观察者(主题)接口 定义主题对象接口 /**抽象主题角色: 这个主题对象在状态上发生变化时,会通知所有观察者对象 也叫事件对象 */ public interface Subject { //增加一 ...
- iOS中常见的设计模式——单例模式\委托模式\观察者模式\MVC模式
一.单例模式 1. 什么是单例模式? 在iOS应用的生命周期中,某个类只有一个实例. 2. 单例模式解决了什么问题? 想象一下,如果我们要读取文件配置信息,那么每次要读取,我们就要创建一个文件实例,然 ...
- Java设计模式(八)观察者模式 迭代器模式
(十五)观察者模式 观察者模式,定义对象间一对多关系,一个对象状态发生改变,全部依赖于它的对象都收到通知而且自己主动更新,观察者与被观察者分开.比如邮件订阅.RSS订阅,假设有更新就会邮件通知你. i ...
- 《Android源码设计模式》--状态模式--责任链模式--解释器模式--命令模式--观察者模式--备忘录模式--迭代器模式
[状态模式] No1: Wifi设置界面是一个叫做WifiSetting的Fragment实现的 No2: 在不同的状态下对于扫描Wifi这个请求的处理是完全不一样的.在初始状态下扫描请求被直接忽略, ...
- NET设计模式 第二部分 行为型模式(18):观察者模式(Observer Pattern)
概述 在软件构建过程中,我们需要为某些对象建立一种“通知依赖关系” ——一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知.如果这样的依赖关系过于紧密,将使软件不能很好地抵御 ...
- java观察者模式
像activeMQ等消息队列中,我们经常会使用发布订阅模式,但是你有没有想过,客户端时如何及时得到订阅的主题的信息?其实就里就用到了观察者模式.在软件系统中,当一个对象的行为依赖于另一个对象的状态 ...
随机推荐
- HDU-1754 I Hate It(线段树,区间最大值)
很多学校流行一种比较的习惯.老师们很喜欢询问,从某某到某某当中,分数最高的是多少. 这让很多学生很反感. 不管你喜不喜欢,现在需要你做的是,就是按照老师的要求,写一个程序,模拟老师的询问.当然,老师 ...
- R语言基础篇——数据对象
1.基本数据类型(numeric,logical,character,NA,double,complex,integer) 2.日期变量 常用函数 Sys.Date()-返回系统当前的日期,Sys.t ...
- WPF绑定并转换
首先新建个项目,我的项目名叫BindConverterDemo,你的话什么都可以,我这里只是做demo 再建两个类,DataDemo,ConverterDemo 这个是DataDemo类 public ...
- em、rpx和px的换算
rpx:对于小程序开发,所用的单位都是rpx,而不论哪个型号的手机,屏幕宽度都是750rpxrpx与px的转换,根据设计稿换算例如:设计稿750px宽度,ps上量出或者标出的宽度是多少,那么就定义多少 ...
- 求助:关于shell数值比较的错误提示
今天写了个脚本,过不了错误这一关,求大神路过瞟一眼. 1 #!/bin/bash 2 #disk use 3 disk_use() { 4 DISK_LOG=/tmp/disk_use.tmp 5 D ...
- SQL Server 2008将数据库数据导出到脚本
1.在要到处的数据库上右键 2.选择“任务” 3.选择“生成脚本” 4.选定要导出的数据库 5.在“编写数据的脚本”处选择“True” 6.接下来选定要导出的表,然后选择“完成”
- sigprocmask()函数学习笔记
sigprocmask()函数用于改变进程的当前阻塞信号集,也可以用来检测当前进程的信号掩码. 函数原型: int sigprocmask(int how, const sigset_t *restr ...
- R语言 Keras Training Flags
在需要经常进行调参的情况下,可以使用 Training Flags 来快速变换参数,比起直接修改模型参数来得快而且不易出错. https://tensorflow.rstudio.com/tools/ ...
- Redis-缓存击穿/穿透/雪崩
缓存击穿/穿透/雪崩 Intro 使用缓存需要了解几个缓存问题,缓存击穿.缓存穿透以及缓存雪崩,需要了解它们产生的原因以及怎么避免,尤其是当你打算设计自己的缓存框架的时候需要考虑如何处理这些问题. 缓 ...
- webdriver显式和隐式等待、强制等待
implicitly_wait() 方法是隐式等待,用来设置超时,一般把implicitly_wait()方法调用在加载测试地址后,等待所测试的应用程序加载WebDriverWait() 是显式等待, ...