委托模式是软件设计模式中的一项基本技巧。在委托模式中,有两个对象参与处理同一个请求,接受请求的对象将请求委托给另一个对象来处理。委托模式是一项基本技巧,许多其他的模式,如状态模式、策略模式、访问者模式本质上是在更特殊的场合采用了委托模式。委托模式使得我们可以用聚合来替代继承.
在C#中,委托由delegate实现,在Java中并没有委托机制,所以我们可以选择用反射来实现委托,下面看看具体的代码.
通知者(主题)实现:
package 事件委托模式;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
/**
* 主题类
* 在订阅了主题后(将需要执行的方法或者参数加入主题后),在主题发出响应时,可以自动执行set中的方法.
*/
public class Subject {
private final Set<ObjectMethodAndParameters> set = new HashSet<>();
/**
* 将一个需要执行的对象以及方法加入到主题的集合中
* @param obj 需要执行的对象
* @param methodName 需要执行的方法名称
* @param parameterizedTypes 需要执行的方法的参数类型
* @param params 需要执行的方法的具体参数
*/
public void Attach(Object obj, String methodName,Class<?>[] parameterizedTypes,Object[] params) {
ObjectMethodAndParameters objectMethodAndParameters = new ObjectMethodAndParameters(obj, methodName, parameterizedTypes,params);
set.add(objectMethodAndParameters);
}
/**
* 将一个需要执行的对象以及方法从主题中删除
* @param obj 需要执行的对象
* @param methodName 需要执行的方法名称
* @param parameterizedTypes 需要执行的方法的参数类型
* @param params 需要执行的方法的具体参数
*/
public void Detach(Object obj,String methodName,Class<?>[] parameterizedTypes,Object[] params) {
ObjectMethodAndParameters object = new ObjectMethodAndParameters(obj, methodName, parameterizedTypes,params);
set.removeIf(next -> next.equals(object));
}
/**
* 执行所有订阅了主题的方法
* @throws NoSuchMethodException 没有找到对应的方法
* @throws InvocationTargetException 被调用的方法或构造函数引发的异常
* @throws IllegalAccessException 对应方法因权限问题不允许方法
*/
public void NotifyAll() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
for (ObjectMethodAndParameters next : set) {
//获取需要执行的对象本体,需要执行的方法名称,以及参数类型
Object object = next.getObject();
String methodName = next.getMethodName();
Class<?>[] parameterizedTypes = next.getParameterizedTypes();
//通过方法名称以及对象类型获取Method实例
Class<?> aClass = object.getClass();
Method method = aClass.getDeclaredMethod(methodName, parameterizedTypes);
//获取返回值类型(其实我认为在委托模式下一般不用处理返回值)
Class<?> returnType = method.getReturnType();
if (!returnType.getTypeName().equals("void")) {
//获取返回值
Object result = method.invoke(object, next.getParams());
System.out.println("返回值:"+result.toString());
} else {
//无返回值方法
method.invoke(object, next.getParams());
}
}
}
public static void main(String[] args) {
//构造主题
Subject subject = new Subject();
//构造观察者A和观察者B
ObserverA observerA = new ObserverA("A");
ObserverB observerB = new ObserverB();
//空参方法的委托(将观察者A的getName方法委托给主题执行)
subject.Attach(observerA,"getName",new Class<?>[]{},new Object[]{});
//有参方法的委托(将观察者B的returnDouble方法委托给主题执行)
Class<?>[] classesB= new Class<?>[]{String.class};
Object[] objectsB = new Object[]{"B"};
subject.Attach(observerB,"returnDouble",classesB,objectsB);
try {
//主题发生改变,调用所有订阅了主题的方法
subject.NotifyAll();
} catch (NoSuchMethodException e) {
System.out.println("没有找到对应方法,请检查参数");
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
System.out.println("访问权限异常,请检查后重试");
e.printStackTrace();
}
}
}
package 事件委托模式;
import java.lang.reflect.ParameterizedType;
public class ObjectMethodAndParameters {
private final Object object;
private final String methodName;
private final Class<?>[] parameterizedTypes;
private final Object[] params;
ObjectMethodAndParameters(Object object,String methodName,Class<?>[] parameterizedTypes,Object[] params) {
this.object = object;
this.methodName = methodName;
this.parameterizedTypes = parameterizedTypes;
this.params = params;
}
public Object getObject() {
return object;
}
public Class<?>[] getParameterizedTypes() {
return parameterizedTypes;
}
public String getMethodName() {
return methodName;
}
public Object[] getParams() {
return params;
}
//刚好的实现是重写HashCode方法
@Override
public boolean equals(Object object) {
//非空判断
if (object == null) {
return false;
}
//判断类型
Class<?> aClass = object.getClass();
if (!(aClass == ObjectMethodAndParameters.class)) {
return false;
}
//判断具体参数
ObjectMethodAndParameters temp = (ObjectMethodAndParameters) object;
if (temp.getObject() == this.getObject() && temp.getMethodName().equals(this.getMethodName())
&&temp.getParameterizedTypes() == this.getParameterizedTypes() && temp.getParams() == this.getParams()) {
return true;
}
return false;
}
}
观察者A类实现:
package 事件委托模式;
public class ObserverA {
private final String name;
ObserverA(String name) {
this.name = name;
}
public String getName() {
System.out.println("委托A执行成功");
return name;
}
}
观察者B类实现:
package 事件委托模式;
public class ObserverB {
public String returnDouble(String name) {
System.out.println("委托B执行成功");
return name +name;
}
}