代理模式:为其他对象提供一种代理以控制这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
UML图
优点:
1、职责清晰:真实的角色就是实现实际的业务逻辑,不用关心其他非本职责的事务,通过后期的代理完成事务,附带的结果就是变成简洁清晰。
2、代理对象可以在客户端和目标对象之间起到中介的作用,这样起到了中介的作用和保护了目标对象的作用。
3、高扩展性
模式结构:一个是真正的你访问的对象(目标类),一个是代理对象,真正对象与代理对象实现同一个接口,先访问代理类再访问真正要访问的对象。
分类:静态代理
业务背景,为一个方法添加日志:开始执行,执行成功,执行失败!
1、没有使用代理的情况
public void addUser(String userId, String userName) {
System.out.println("start--->>>>addUser()");
try {
System.out.println("UserManagerImp.addUser()-->>" + userId);
System.out.println("success--->>>>addUser()");
} catch (Exception e) {
System.out.println("error--->>>>addUser()");
}
}
弊端:多个方法在实现过程中都需要添加“
开始执行,执行成功,执行失败”的方法!
2、使用静态代理的情况
//实现类
public class UserManagerImp implements UserManager {
public void addUser(String userId, String userName) {
try {
System.out.println("UserManagerImp.addUser()-->>" + userId);
} catch (Exception e) {
}
}
}
//代理类
public class UserManaegrImplProxy implements UserManager {
//引用目标类,使用构造函数
private UserManager userManager;
public UserManaegrImplProxy(UserManager userManager)
{
this.userManager= userManager;
}
public void addUser(String useId, String userName) {
System.out.println("start--->>>>addUser()");
try {
userManager.addUser(useId, userName);
System.out.println("success--->>>>addUser()");
} catch (Exception e) {
e.printStackTrace();
System.out.println("error--->>>>addUser()");
}
}
}
优点:保证了目标的独立性,将添加日志的方法移植到了代理类中,注意代理类与目标类同实现一个接口(具有相同的方法),Client端调用的时候通过调用代理类来实现调用目标类。
弊端:代理类中的每个方法下都需要添加日志操作。
时序图
3、使用动态代理的情况
主要是利用了反射的机制,通过对java.lang.reflect中的InvocationHandler接口的实现,对代理类实现进一步的抽象。有如下介绍
Proxy代理类具有newProxyInstance()的静态方法(Proxy:
provides static methods for creating dynamic proxy classes and instances, and it is also the superclass of all dynamic proxy classes created by those methods. )
newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h):加载目标类,目标类实现的接口,以及实现InvocationHandler接口的类。
代码实现如下:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class LogHandler implements InvocationHandler {
private Object targetObject;
public Object newProxyInstance(Object targetObject)
{
this.targetObject=targetObject;
return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
targetObject.getClass().getInterfaces(), this);
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("start--->>" + method.getName());
for(int i=0; i<args.length; i++){
System.out.println(args[i]);
}
Object ret= null;
try {
//调用目标类方法
method.invoke(targetObject, args);
System.out.println("success--->>" + method.getName());
} catch (Exception e) {
e.printStackTrace();
System.out.println("error--->>" + method.getName());
throw e;
}
return ret;
}
}
main函数调用
public static void main(String[] args) {
//使用代理类调用目标
LogHandler logHandler= new LogHandler();
UserManager userManager=(UserManager)logHandler.newProxyInstance(new UserManagerImp());
userManager.addUser("001", "张三");
}
时序图:
优点:实现了目标类的独立性,代理类通过反射和抽象实现了更好的复用性,减少代码量。
弊端:使用了反射机制,会影响性能。
学习认识:在学习大话模式的时候大家都记得通过代理去找MM送花的故事,当时对代理模式有了一个感性的认识,经过对反射的学习,再学习代理模式,有种原来是这么简单。反复的学习带来更深刻的认知。