代理模式:
代理模式给某个对象提供了一个代理对象,并由代理对象控制对原对象的引用。
代理分为静态代理和动态代理。
为何用代理?
不用代理时,在写实现接口类UserManagerImpl的时候代码是这样写的:
public void addUser(String userId, String userName) {
System.out.println("start-->>addUser() userId-->>" + userId);
try {
System.out.println("UserManagerImpl.addUser() userId-->>" + userId);
System.out.println("success-->>addUser()");
}catch(Exception e) {
e.printStackTrace();
System.out.println("error-->>addUser()");
throw new RuntimeException();
}
}
我们的需求是调用每个像addUser()这样的方法都需要加上日志记录,开始需要记录,成功需要记录,错误也需要记录,这样如果该类中方法很多的话,在维护的时候就会很难,为了遵守OCP,我们索性抽出一个代理类,代真正的实现类去执行一些操作,所以就用到了代理模式。
第一版重构:
使用静态代理:
调用流程图:
代理类部分代码实现:
public class UserManagerImplProxy implements UserManager {
private UserManager userManager;
public UserManagerImplProxy(UserManager userManager) {
this.userManager = userManager;
}
public void addUser(String userId, String userName) {
try {
System.out.println("start-->>addUser() userId-->>" + userId);
userManager.addUser(userId, userName);
System.out.println("success-->>addUser()");
}catch(Exception e) {
e.printStackTrace();
System.out.println("error-->>addUser()");
}
}
}
静态代理解决了OCP的问题,但同样存在其他问题:
1、如果系统足够大,需要建立大量的代理类
2、重复代码出现在各个地方,违背原则:重复代码最好不要出现多次。
第二版重构:
使用动态代理:
调用流程图:
代码实现:
Client类:
public static void main(String[] args) {
LogHandler logHandler = new LogHandler();
//userManager是一个代理对象
UserManager userManager = (UserManager)logHandler.newProxyInstance(new UserManagerImpl());
//userManager.addUser("0001", "张三");
//userManager.delUser("0001");
String name = userManager.findUser("0001");
System.out.println("Client.main() --- " + name);
}
LogHandler类:
public class LogHandler implements InvocationHandler {
private Object targetObject;
//this相当于一个代理对象
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 {
//调用目标方法,方法有返回值,ret不为空;方法无返回值,ret默认null;该method为findUser(),根据Client传过来,动态识别
ret = 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;
}
}
动态代理:在运行时创建代理类,JDK动态代理只能对实现了接口的类进行代理,意思是,用LogHandler代理UserManagerImpl,前提是UserManagerImpl必须实现UserManager接口。
感谢您的阅读!