Java 实现委托+事件
上篇提到了观察者模式的实现依赖倒转原则,尽管已经实现了依赖倒转原则,但“抽象通知者”,还是依赖“抽象观察者”,也就是说万一没有了抽象观察者这样的接口,通知功能就完成不了。另外就是每一个观察者,它不一定都需要接收到通知的。
知识补充:
委托
是对函数的封装,可以当作给方法的特征指定一个名称。而
事件
则是委托的一种特殊形式,当发生有意义的事情时,事件对象处理通知过程)
什么是事件?
在C#中,
事件
就是一个宽泛的、无具体实现的事情,事件是宽泛的、只代表概念而不代表实现,具体的事件触发是通过委托调用实现方法来。
一、举例:猫和老鼠(委托与事件)
1、建一个控制台应用系统:
我们的需求:有一个猫叫Tom,有两只老鼠叫Jerry和Jack,Tom只要一叫“喵,我是Tom”,两只老鼠就说“老猫来了,快跑”。
2、分析需要几个类以及类和类之间的关系:
当Cat的Shout方法触发时,老鼠Mouse就执行Run方法。不过这里如何用Shout触发让Mouse就执行Run方法。由于猫是不认识老鼠的,所以不能在Cat类中引用Mouse对象。
这时,就用到了委托事件的方法了。
二、Java实现C#中的委托和事件:
1、委托类:
委托是一种引用方法的类型。一旦委托分配了方法,委托将与该方法具有完全相同的行为。
package 猫和老鼠_委托;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
//委托类
public class Delegate {
private Object obj;
private String methodName;
private Object[] methodParameter;
private Class<?>[] methodType;
public Delegate(){}
public Delegate(Object obj, String methodName, Object...methodParameter) {
this.obj = obj;
this.methodName = methodName;
this.methodParameter = methodParameter;
int len=methodParameter.length;
this.methodType = new Class[len];
for(int i=0;i<len;i++){
methodType[i]=methodParameter[i].getClass();
}
}
public void invoke() throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
Method m=obj.getClass().getDeclaredMethod(methodName, methodType);
m.invoke(obj, methodParameter);
}
}
2、事件类:
package 猫和老鼠_委托;
import java.lang.reflect.InvocationTargetException;
import java.util.Vector;
//事件
public class Event {
private Vector<Delegate> vs=new Vector<Delegate>();
public void invoke() throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
for(Delegate d:vs){
d.invoke();
}
}
public void addDelegate(Delegate delegate){
System.out.println(delegate.toString());
vs.add(delegate);
}
public void delDelegate(Delegate delegate){
vs.remove(delegate);
}
}
3、被委托者:Cat猫类
package 猫和老鼠_委托;
import java.lang.reflect.InvocationTargetException;
public class Cat {
private String name;
private Event event;
public Cat(String name){
this.name=name;
event =new Event();
}
public void addDelegate(Object obj, String methodName, Object...methodParameter){
Delegate d=new Delegate(obj,methodName, methodParameter);
event.addDelegate(d);
}
public void delDelegate(Object obj, String methodName, Object...methodParameter){
Delegate d=new Delegate(obj, methodName, methodParameter);
event.delDelegate(d);
}
public void action() throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
System.out.println("我是"+name+",我来抓老鼠了!");
event.invoke();
}
}
4、委托者:Mouser1,Mouser2老鼠类
package 猫和老鼠_委托;
//委托者
public class Mouse1 {
private String name;
public Mouse1(String name){
this.name=name;
}
public void shout(String name){
System.out.println(name+"来了,我是"+this.name+",我要快跑!");
}
}
package 猫和老鼠_委托;
public class Mouse2 {
private String name;
public Mouse2(String name){
this.name=name;
}
public void speak(String name){
System.out.println(name+"来了,我是"+this.name+",我要快跑!");
}
}
5、客户端:Client
package 猫和老鼠_委托;
import java.lang.reflect.InvocationTargetException;
public class Client {
public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
// TODO Auto-generated method stub
Cat cat=new Cat("Tom");
Mouse1 m1=new Mouse1("Jerry");
Mouse2 m2=new Mouse2("Jack");
cat.addDelegate(m1, "shout", "Tom");
cat.addDelegate(m2, "speak", "Tom");
cat.action();
}
}
6、运行结果:
这样就相当于c#的委托了,这样也改掉了观察者模式的缺点,通知者类完全不知道自己需要通知的是谁,做到了完全解耦,同时也去掉了抽象的观察者类。