Java 实现(观察者模式)委托+事件

  • Post author:
  • Post category: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#的委托了,这样也改掉了观察者模式的缺点,通知者类完全不知道自己需要通知的是谁,做到了完全解耦,同时也去掉了抽象的观察者类。



版权声明:本文为m0_51506743原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。