订阅者模式
订阅者和发布者模式,通常用于消息队列中。一般有两种形式来实现消息队列,一是使用生产者和消费者来实现,二是使用订阅-发布者来实现。其中使用订阅者和发布者实现消息队列的方式,就会用订阅者模式。
所谓的订阅者,就像我们在日常生活中,订阅报纸一样。我们订阅报纸的时候,通常都得需要在报社或者一些中介机构进行注册。当有新版的报纸发刊的时候,邮递员就需要向订阅该报纸的人,依次发放报纸。因此代码实现该模式,通常需要两个步骤:
1、初始化发布者、订阅者。
2、订阅者需要注册到发布者,发布者发布消息时,依次向订阅者发布消息。
订阅者注册
发布者发布消息
代码实现如下(一个常见的例子,双十一商品打折,只有关注该商品的客户才能收到该商品打折的信息):
商品信息类主要有成员变量来存放所有关注该商品的顾客(ArrayList),同时存在发布消息的方法,客户关注商品的方法(即向客户容器中添加客户)等。
//商品类
classProduct{
private ArrayList clientArrayList =newArrayList();
public voidnotify(String info){
//对于所有关注该商品的顾客进行遍历,依次将信息发布出去
for(Client client:clientArrayList){
client.receiveInfo(info);
}
}
publicvoidregister(Client client){
clientArrayList.add(client);
}
}
客户类,即订阅者,用来接受商品(发布者)发布的打折信息:
class ConcreteClient{
privateString name;
publicConcreteClient(String name){
this.name = name;
}
//用来接受发布者发布的消息
public void receiveInfo(String info){
System.out.println(this.name +":收到信息("+ info +")");
}
}
测试:
@Test
public void test(){
Product product =newProduct();//a 用户关注商品 product.register(newConcreteClient("a"));//b 用户关注商品 product.register(newConcreteClient("b"));//c 用户关注商品 product.register(newConcreteClient("c"));//d 用户关注商品 product.register(newConcreteClient("d")); product.notify("商品编号为D1403121717大减价");
}
运行结果:
a:收到信息(商品编号为D1403121717大减价)
b:收到信息(商品编号为D1403121717大减价)
c:收到信息(商品编号为D1403121717大减价)
d:收到信息(商品编号为D1403121717大减价)
事件监听器模式
概念
事件监听器模式重要的三个概念:事件+事件监听器+事件源
1、在javascript中,这样的模式很常见,例如:
$("#div").addEventListener("click",function(event){});
事件源:$("#div") 即id = div的html元素
事件:click事件对应的对象
事件监听器:function(event){ } 匿名函数
2、在java awt编程中:
Button button =newButton();
button.addActionListener(newActionListener(){
publicvoidactionPerformed(ActionEvent actionEvent){
//当触发事件时,执行代码
}
});
事件源:Button组件
事件:click事件对应的对象 ActionEvent
事件监听器:ActionListener接口中的actionPerformed方法
事件监听的过程如下:
1、事件源通常会有很多事件类型,比如点击类型,加载类型,关闭类型等等。此时,事件源就会添加这些个事件对应的事件监听器。
2、事件监听器的作用就是:当事件源的某个事件被触发时,就会调用这个事件对应的事件监听器的处理事件的方法。
因此使用代码实现事件监听器模式,需要以下过程:
初始化事件源类,事件监听器所在的类(实现接口EventListener),事件类(继承EventObject类)。
对于每一个事件,都分为更为具体的事件(如点击事件,分为双击和单击。加载事件,分为开始加载,成功加载,加载异常,关闭页面等事件)。点击事件对应ClickEvent,其种类可以分为DoubleClick和SingleClick事件(通常使用ClickEvent类的类常量表示)。而ClickEvent事件则对应ClickEventListener事件监听器,更为具体的DoubleClick事件对应ClickEventListener事件的doubleClick方法,而SingleClick事件对应ClickEventListener事件的singleClick方法。
确认要触发的事件,实例化事件类,ClickEvent,并且赋值其成员变量,是赋值其为DoubleClick还是SingleClick。
当事件源触发click事件的时候,通过条件判断(if-else/switch-case),则会使用ClickEventListener事件监听器。接下来继续判断click事件的类型和种类,如果是DoubleClick事件,则调用ClickEventListener类的doubleClick方法。如果是SingleClick事件,则调用ClickEventListener类的singleClick方法。
上述处理过程可以用下图表示出来:
具体代码实现过程:
定义三个事件:MouseMovationEvent事件,LoadPageEvent事件,ClickEvent事件
/***页面加载事件*/
class LoadPageEventex tendsEventObject{
privateintid;//表示具体事件的类型
publicstaticfinalintPAGELOAD_SUCCESS =1;//页面加载成功事件 publicstaticfinalintPAGELOAD_ERROR =2;//页面加载失败事件 publicstaticfinalintPAGELOAD_START =3;//页面开始加载事件 publicstaticfinalintPAGELOAD_CLOSE =4;//页面关闭事件
//建立LoadPageEvent实例对象,要指明具体的id类型,构造函数根据id来指定具体的事件类型
public LoadPageEvent(Object source,intid){
super(source);
switch(id){
casePAGELOAD_CLOSE:this.id = PAGELOAD_CLOSE;break;
casePAGELOAD_ERROR:this.id = PAGELOAD_ERROR;break;
casePAGELOAD_START:this.id = PAGELOAD_START;break;
casePAGELOAD_SUCCESS:this.id = PAGELOAD_SUCCESS;break;
}
}
public LoadPageEvent(Object source){
super(source);
}//获取事件的具体的事件类型
publicintgetId(){
returnthis.id;
}
}/**
* 点击事件
*/class
ClickEvent extends EventObject{
//具体的事件类型
privateintid;
public final static int SINGLE_CLICK =1;//单击事件
publicfinalstaticintDOUBLE_CLICK =2;//双击事件
public ClickEvent(Object source){
super(source);
}
//建立ClickEvent实例对象,要指明具体的id类型,构造函数根据id来指定具体的事件类型public ClickEvent(Object source,intid){
super(source);
switch(id){
caseSINGLE_CLICK:this.id = SINGLE_CLICK;break;
caseDOUBLE_CLICK:this.id = DOUBLE_CLICK;break;
}
}
publicintgetId(){returnthis.id;
}}/**
* 鼠标移动事件
*/class MouseMovationEvent extends EventObject{
//具体的事件类型privateintid;publicstaticfinalintMOVE_LEFT =0;//鼠标左移事件
public static final int MOVE_RIGHT =1;//鼠标右移事件
//建立MouseMovationEvent实例对象,要指明具体的id类型,构造函数根据id来指定具体的事件类型
public MouseMovationEvent(Object source,intid){
super(source);switch(id){
caseMOVE_LEFT:this.id = MOVE_LEFT;break;
caseMOVE_RIGHT:this.id = MOVE_RIGHT;break;
}
}
public MouseMovationEvent(Object source){super(source);
}
publicintgetId(){
returnthis.id;
}
}
定义三个事件监听器:MouseMovationEventListener监听器,LoadPageEventListener事件监听器,ClickEventListener事件监听器
////////////////////页面加载事件监听器//////////////////classLoadPageListenerimplementsEventListener{//LoadPageEvent的成功加载事件触发时,则执行该方法publicvoidonSuccess(LoadPageEvent e){ System.out.println("页面加载成功"); }//LoadPageEvent的开始加载事件触发时,则执行该方法publicvoidonStart(LoadPageEvent e){ System.out.println("页面开始加载"); }//LoadPageEvent的关闭事件触发时,则执行该方法publicvoidonClose(LoadPageEvent e){ System.out.println("页面关闭"); }//LoadPageEvent的异常加载事件触发时,则执行该方法publicvoidonError(LoadPageEvent e){ System.out.println("页面加载出错"); }}///////////页面点击监听器///////////////////classClickListenerimplementsEventListener{//ClickEvent的单击事件触发时,则执行该事件publicvoidonSingle(ClickEvent clickEvent){ System.out.println("鼠标单击"); }//ClickEvent的双击事件触发时,则执行该事件publicvoidonDouble(ClickEvent clickEvent){ System.out.println("鼠标双击"); }}///////////鼠标移动监听器///////////////////classMouseMovationListenerimplementsEventListener{//MouseMovationEvent的左移事件触发时,则执行该方法publicvoidonLeft(MouseMovationEvent mouseMovationEvent){ System.out.println("鼠标左划"); }//MouseMovationEvent的右移事件触发时,则执行该方法publicvoidonRight(MouseMovationEvent mouseMovationEvent){ System.out.println("鼠标右划"); }}
定义一个事件源:Page页面。事件源至少有两个方法,一个是为自身添加事件监听器,一个是触发事件方法。当触发事件时,会根据传入的事件获取事件类型。从而确定应该实例化哪一个事件监听器类,并且调用事件监听器的哪一个方法。
///////////////事件源////////////classPage{privateLoadPageListener loadPageListener;privateClickListener clickListener;privateMouseMovationListener mouseMovationListener;//为自身注册事件监听器publicvoidaddLoadPageListener(LoadPageListener loadPageListener){this.loadPageListener = loadPageListener; }publicvoidaddClickListener(ClickListener clickListener){this.clickListener = clickListener; }publicvoidaddMouseMovationListener(MouseMovationListener mouseMovationListener){this.mouseMovationListener = mouseMovationListener; }//触发事件publicvoidtrigger(EventObject e){//判断事件类型,确定使用的事件监听器类,并且确定调用事件监听器类的哪个方法。if(einstanceofLoadPageEvent){ LoadPageEvent le = (LoadPageEvent)e;switch(le.getId()){caseLoadPageEvent.PAGELOAD_CLOSE:this.loadPageListener.onClose(le);break;caseLoadPageEvent.PAGELOAD_ERROR:this.loadPageListener.onError(le);break;caseLoadPageEvent.PAGELOAD_START:this.loadPageListener.onStart(le);break;caseLoadPageEvent.PAGELOAD_SUCCESS:this.loadPageListener.onSuccess(le);break; } }elseif(einstanceofClickEvent){ ClickEvent ce = (ClickEvent)e;switch(ce.getId()){caseClickEvent.DOUBLE_CLICK:this.clickListener.onDouble(ce);break;caseClickEvent.SINGLE_CLICK:this.clickListener.onSingle(ce);break; } }elseif(einstanceofMouseMovationEvent){ MouseMovationEvent me = (MouseMovationEvent)e;switch(me.getId()){caseMouseMovationEvent.MOVE_LEFT:this.mouseMovationListener.onLeft(me);break;caseMouseMovationEvent.MOVE_RIGHT:this.mouseMovationListener.onRight(me);break; } } }}
以上代码均在Intellij Idea环境下测试通过。
來源:简书 https://www.jianshu.com/p/40986c26315a