一文搞懂Java事件委托(观察者模式的拓展)
引言:
本文的前提是你要了解一下观察者模式的结构。
这是《大话设计模式》中关于观察者模式的结构图,两个抽象类两个具体类。Subject是通知者,Observer是观察者,当通知者执行Notify方法时,Notify方法会循环执行所有观察者的Update方法。实现一个通知执行的功能。如果你有一个需求,当事件A发生时,相应的事件B、事件C也会相应执行,但要通知的事件数量和内容都不固定,且与事件A逻辑关系不大,那么把事件BC写在事件A中就不合理了,此时采用观察者模式是个不错的选择。
观察者模式的缺点:
通过结构图可以看到,通知者需要包含Observer接口对象,相耦合,另外,所有的通知者都需要实现Observer接口并实现update()方法,这是很拘板的。全新开发的项目还好,关联老项目就麻烦了,比如当用户注册成功时需要给他发送一封邮件,而发送邮件方法是已有的
public Class EmailUtil {
public sendEmail(){
//do something
}
}
如果我们用观察者模式实现,必须
public Class EmailUtil implements Observer{
public sendEmail(){
//do something
}
@Override
public void update() {
this.sendEamil();
}
}
或者要新建一个观察者类来实现Observer接口,是不是很麻烦,为啥不可以直接委托给sendEmail()呢?
事件委托登场:
大家好,我是事件委托,之所以我那么成功还是得感谢java反射,否则我将一事无成。其实我做的东西很简单,原本我是调用Observer.update方法,现在改为Object.getClass().getMethod().invoke(object,params)。这样就解决了必须要实现Observer接口实现update()方法的问题了。
我们来看看现在的Observer,现在定义成一个事件:
package designPattern.Observer_delegate;
import java.lang.reflect.Method;
/**
* <pre>类名: Event</pre>
* <pre>描述: 通过反射,实现对事件的封装</pre>
* <pre>版权: web_chen@163.com</pre>
* <pre>日期: 2020/3/19 14:19</pre>
* <pre>作者: chenwb</pre>
*/
public class Event {
private Object target;
private String methodName;
private Object[] params;
private Class[] paramsTypes;
public Event(Object target, String methodName, Object[] params) {
this.target = target;
this.methodName = methodName;
this.params = params;
createParamsTypes(params);
}
/**
* @Description: 获取参数类型,反射时用
* @author chenwb
* @date 2020/3/19 14:55
* @param params
*/
private void createParamsTypes(Object[] params) {
paramsTypes = new Class[params.length];
for (int i = 0; i < params.length; i++) {
paramsTypes[i] = params[i].getClass();
}
}
/**
* @Description: invoke方法,就是Observer的update方法
* @author chenwb
* @date 2020/3/19 14:55
*/
public void invoke() {
Method method = null;
try {
method = target.getClass().getMethod(methodName, paramsTypes);
method.invoke(target, params);
} catch (Exception e) {
System.out.println("委托执行异常,异常原因:" + e.getMessage());
// no to do
}
}
}
现在的通知者:
package designPattern.Observer_delegate;
import java.util.ArrayList;
import java.util.List;
/**
* <pre>类名: EventHandler</pre>
* <pre>描述: 事件执行器,封装事件</pre>
* <pre>版权: web_chen@163.com</pre>
* <pre>日期: 2020/3/19 14:19</pre>
* <pre>作者: chenwb</pre>
*/
public class EventHandler {
private List<Event> eventList = new ArrayList<>();
public boolean addEvent(Event event) {
return eventList.add(event);
}
/**
* @Description: 添加委托事件
* @author chenwb
* @date 2020/3/19 14:20
* @param object 事件执行目标
* @param methodName 事件执行方法
* @param args 执行参数
*/
public void addEvent(Object object, String methodName, Object... args) {
eventList.add(new Event(object, methodName, args));
}
/**
* @Description: 事件循环执行
* @author chenwb
* @date 2020/3/19 14:21
*/
public void handle() {
for (Event e : eventList) {
e.invoke();
}
}
}
为了让具体的业务类更加简单,我们把通知这件事抽成抽象类:
package designPattern.Observer_delegate;
/**
* <pre>类名: DefaultDelegation</pre>
* <pre>描述: 默认委托,提供了默认实现</pre>
* <pre>版权: web_chen@163.com</pre>
* <pre>日期: 2020/3/19 14:19</pre>
* <pre>作者: chenwb</pre>
*/
public abstract class DefaultDelegation {
private EventHandler eventHandler = new EventHandler();
/**
* @Description: 新增委托
* @author chenwb
* @date 2020/3/19 13:46
* @param target 目标类
* @param methodName 目标方法
* @param args args 可变入参
* @return void
*/
public void addListeners(Object target, String methodName, Object... args) {
eventHandler.addEvent(target, methodName, args);
}
/**
* @Description: 通知他人
* @author chenwb
* @date 2020/3/19 14:17
* @return void
*/
public void notifyOthers() {
eventHandler.handle();
}
/**
* 获取eventHandler
* @return eventHandler
*/
public EventHandler getEventHandler() {
return eventHandler;
}
/**
* 设置eventHandler
* @param eventHandler eventHandler
*/
public void setEventHandler(EventHandler eventHandler) {
this.eventHandler = eventHandler;
}
}
以基民委托基金经理的买股票为例,继承通知的逻辑:
package designPattern.Observer_delegate;
/**
* <pre>类名: FundInvestor</pre>
* <pre>描述: 基民(买基金的人)</pre>
* <pre>版权: web_chen@163.com</pre>
* <pre>日期: 2020/3/19 14:22</pre>
* <pre>作者: chenwb</pre>
*/
public class FundInvestor extends DefaultDelegation {
private String name;
public FundInvestor(String name) {
this.name = name;
}
/**
* @Description: 买基金
* @author chenwb
* @date 2020/3/19 14:22
*/
public void buyFund() {
System.out.println(name + "买基金!");
//委托事件 可以委托任何事件
notifyOthers();
}
}
基金经理(正常逻辑,不需要事先事先Observer接口,与基民是没有耦合的):
package designPattern.Observer_delegate;
/**
* <pre>类名: FundManager</pre>
* <pre>描述: 基金经理</pre>
* <pre>版权: web_chen@163.com</pre>
* <pre>日期: 2020/3/19 14:22</pre>
* <pre>作者: chenwb</pre>
*/
public class FundManager {
private String name;
public FundManager(String name) {
this.name = name;
}
/**
* @Description: 买股票A
* @author chenwb
* @date 2020/3/19 14:22
*/
public void buyStockA() {
System.out.println(name + "经理买股票A");
}
/**
* @Description: 买股票B
* @author chenwb
* @date 2020/3/19 14:22
*/
public void buyStockB() {
System.out.println(name + "经理买股票B");
}
}
客户端类:
package designPattern.Observer_delegate;
public class TradeCenter {
public static void main(String[] args) {
FundInvestor fundInvestor = new FundInvestor("小张");
FundManager fundManager = new FundManager("天弘");
fundInvestor.addListeners(fundManager,"buyStockA");
fundInvestor.addListeners(fundManager,"buyStockB");
fundInvestor.buyFund();
}
}
如果需要买股票A,只要绑定buyStockA方法即可。
相比观察者模式,事件委托相对更加灵活。
还没有评论,来说两句吧...