代理模式(Proxy)
1、概念
代理模式为其他对象提供一个代理以控制对这个对象的访问,属于结构性模式。从代码的角度来分,代理可以分为两种:一种是静态代理,另一种是动态代理。
静态代理就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。
动态代理类的源码是在程序运行期间根据反射等机制动态的生成,所以不存在代理类的字节码文件。代理类和委托类的关系是在程序运行时确定。
2、模式结构
- Subject(抽象主题类):接口或者抽象类,声明真实主题与代理的共同接口方法。
- RealSubject(真实主题类):也叫做被代理类或被委托类,定义了代理所表示的真实对象,负责具体业务逻辑的执行,客户端可以通过代理类间接的调用真实主题类的方法。
- Proxy(代理类):也叫委托类,持有对真实主题类的引用,在其所实现的接口方法中调用真实主题类中相应的接口方法执行。
3、使用场景
- 当一个对象不能或者不想直接访问另一个对象时,可以通过一个代理对象来间接访问
- 被访问的对象不想暴露全部内容时,可以通过代理去掉不想被访问的内容
- 一个消耗资源较少的对象来代表一个消耗资源较多的对象,从而降低系统开销、缩短运行时间时
4、优缺点
优点:
- 协调调用者和被调用者,降低了系统的耦合度
- 代理对象作为客户端和目标对象之间的中介,起到了保护目标对象的作用
- 以一个小对象代理一个大对象,达到优化系统提高运行速度的目的
缺点:
- 调用者和真实主题之间增加了代理对象,因此可能会造成请求的处理速度变慢。
- 实现代理模式需要额外的工作,从而增加了系统实现的复杂度
5、实例
静态实例
public interface IUserDao {
int save();
}
public class UserDao implements IUserDao {
@Override
public int save() {
return 0;
}
}
public class UserDaoProxy implements IUserDao {
//接收保存目标对象
private IUserDao target;
public UserDaoProxy(IUserDao target) {
this.target = target;
}
@Override
public int save() {
return target.save();
}
}
动态实例:
还是使用静态代理的IUserDao和UserDao 类,改造UserDaoProxy 类,利用java的newProxyInstance动态生成实例。
public class UserDaoProxy {
//维护一个目标对象
private Object target;
public UserDaoProxy(Object target) {
this.target = target;
}
//给目标对象生成代理对象
public Object getProxyInstance() {
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//运用反射执行目标对象方法
Object returnValue = method.invoke(target, args);
return returnValue;
}
}
);
}
}
public static void main(String[] args) {
// 目标对象
IUserDao target = new UserDao();
System.out.println(target.getClass());
// 给目标对象,创建代理对象
IUserDao proxy = (IUserDao) new UserDaoProxy(target).getProxyInstance();
proxy.save();
}