代理模式(Proxy)
Protection Proxy:检查调用者是否具有实现一个请求所必须的访问权限
理解:比如真实对象实现的功能是访问一个网站,将这个对象交给一个代理对象去代理,用户访问网站时是通过调用代理对象访问,这时代理对象除了调用真实对象的访问方法,还可以加上自己的操作,比如先检测用户受否有这个请求权限再决定是否调用该真实对象的访问方法。
通过使用代理,真实的对象只需要实现其现有的功能,而一些附加的功能操作后面可以通过代理对象来添加。
Virtual Proxy:可以缓存实体的附加信息,以便延迟对它的访问
理解:打开一个程序,并不需要一次性加载所有的信息,有些庞大的信息可以再后面使用到时再加载。这时候就用到一个代理对象,储存真实对象的一些信息和对真实对象的指引,当用户需要真实对象时,代理对象才去实例化真实对象并调用真实对象的方法,来回应用户的请求。
静态代理
特对每一种真实角色都去写一个代理类,代理类和真实类实现了同一个接口,同时将真实类注入代理类中,代理类实现接口的所有方法,除了调用真实角色的方法,还可以加上一些公共的代码。对于用户的请求是调用代理角色的方法去响应。
动态代理
设计一个通用的代理类,能够代理不同的真实角色。关键点是Object去接收任何真实角色,然后使用反射获取其接口类型,使用反射调用其接口方法时,附加代理的事务。
java实现动态代理:
package com.sen.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyInvocationHandler implements InvocationHandler {
Object target;
public void setTarget(Object target) {
this.target = target;
}
// 获取一个代理类
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 在调用方法前完成一些事务
log(method.getName());
// 调用接口的方法
Object result = method.invoke(target, args);
// 在调用方法后完成一些事务
// code(do something)
return result;
}
// 事务方法
public void log(String methodName){
System.out.println("[执行了" + methodName + "方法]");
}
}
设计一个真实角色接口,比如增删改查功能
package com.sen.proxy;
public interface Service {
void add();
void delete();
void update();
void query();
}
实现这个接口的真实角色
package com.sen.proxy;
public class ServiceImpl implements Service{
@Override
public void add() {
System.out.println("add");
}
@Override
public void delete() {
System.out.println("delete");
}
@Override
public void update() {
System.out.println("update");
}
@Override
public void query() {
System.out.println("query");
}
}
测试动态代理
package com.sen.proxy;
public class TestProxy {
public static void main(String[] args) {
Service service = new ServiceImpl();
ProxyInvocationHandler pil = new ProxyInvocationHandler();
pil.setTarget(service);
Service proxy = (Service) pil.getProxy();
proxy.add();
proxy.delete();
proxy.update();
proxy.query();
}
}
/*
输出:
[执行了add方法]
add
[执行了delete方法]
delete
[执行了update方法]
update
[执行了query方法]
query
*/
总结:使用动态代理,即使后面换了一个真实角色,比如不再是实现增删改查的功能,而是实现其他功能(比如加减乘除)的角色,这个动态代理类依旧通用。一句话,反射牛逼!