# 代理模式
# 概念
代理模式是一种结构型设计模式,其核心思想是为其他对象提供一种代理,以控制对该对象的访问。代理对象作为客户端和目标对象之间的中介,能够在目标对象执行操作前后添加额外的功能。
# 作用
1.控制对象访问:通过代理对象作为中介,可以管理对目标对象的访问权限,例如根据用户权限决定是否允许访问。
2.增强功能:在不修改目标对象代码的情况下,为其方法添加前置或后置操作,如日志记录、性能监控等。
3.延迟加载:代理对象可以延迟目标对象的实例化,直到真正需要时才创建,避免过早占用内存资源。
4.职责分离:将核心业务逻辑与附加功能分离,符合单一职责原则,提升代码的可维护性。
# 场景
1.访问控制:需要根据用户权限决定是否允许访问目标对象时,如权限校验。
2.日志记录:在访问目标对象前后记录日志信息,便于审计或调试。
3.性能监控:测量目标对象方法的执行时间,用于性能分析或优化。
4.延迟加载:当目标对象创建成本较高时,按需加载资源,如数据库连接或大型对象。
# 举例
# 静态代理
// 目标接口
public interface ITeacher {
void teach();
}
// 目标类
public class Teacher implements ITeacher {
@Override
public void teach() {
System.out.println("老师正在授课");
}
}
// 代理类
public class TeacherProxy implements ITeacher {
private Teacher teacher;
public TeacherProxy(Teacher teacher) {
this.teacher = teacher;
}
@Override
public void teach() {
// 前置操作
System.out.println("开始上课前的准备工作");
teacher.teach();
// 后置操作
System.out.println("课程结束,安排课后作业");
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Teacher teacher = new Teacher();
TeacherProxy proxy = new TeacherProxy(teacher);
proxy.teach();
}
}
# 动态代理
// 目标接口
public interface ITeacher {
void teach();
}
// 目标类
public class Teacher implements ITeacher {
@Override
public void teach() {
System.out.println("老师正在授课");
}
}
// 动态代理类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class DynamicProxy implements InvocationHandler {
private Object target;
public DynamicProxy(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 前置操作
System.out.println("开始上课前的准备工作");
Object result = method.invoke(target, args);
// 后置操作
System.out.println("课程结束,安排课后作业");
return result;
}
public Object getProxyInstance() {
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), this);
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Teacher teacher = new Teacher();
DynamicProxy proxy = new DynamicProxy(teacher);
ITeacher iTeacher = (ITeacher) proxy.getProxyInstance();
iTeacher.teach();
}
}
# 反例
如果不使用代理模式,可能需要通过继承目标类并重写方法来实现附加功能,例如:
public class EnhancedTeacher extends Teacher {
@Override
public void teach() {
// 前置操作
System.out.println("开始上课前的准备工作");
super.teach();
// 后置操作
System.out.println("课程结束,安排课后作业");
}
}
这种方式存在以下问题:
1.侵入性修改:需要修改目标类的代码或通过继承来增强功能,违反了开闭原则(对扩展开放,对修改关闭)。
2.复用性差:如果多个目标类需要相同的附加功能(如日志记录),需要为每个类创建子类,导致代码重复。
3.耦合度高:客户端直接依赖具体的增强类(如EnhancedTeacher),当目标类或附加功能变化时,需要修改客户端代码,不利于系统的扩展和维护。
# 原理
代理模式通过引入代理对象,拦截客户端对目标对象的访问请求。在静态代理中,代理类与目标类的关系在编译时确定,通过组合目标对象并在其方法调用前后插入额外逻辑。动态代理则利用反射机制,在运行时动态生成代理类,能够为任何实现了接口的目标对象创建代理,具有更高的灵活性和复用性。
# 缺点
1.性能开销:动态代理在运行时通过反射调用方法,可能带来一定的性能损耗;静态代理虽然性能较好,但需要为每个目标类编写代理类,增加代码量。
2.代码复杂度:无论是静态代理还是动态代理,都需要额外编写代理类或处理代理逻辑的代码,增加了系统的复杂度和维护成本。
总结
代理模式通过代理对象控制对目标对象的访问,并在访问过程中添加额外功能,实现了核心逻辑与附加功能的解耦。其静态代理形式在编译时确定代理关系,动态代理则在运行时生成代理类,提供了更高的灵活性。该模式适用于访问控制、日志记录、性能监控等场景,能够有效避免直接修改目标类代码带来的侵入性问题。然而,代理模式可能引入性能开销和代码复杂度,需根据具体场景权衡使用。

微信公众号

QQ交流群
如若发现错误,诚心感谢反馈。
愿你倾心相念,愿你学有所成。
愿你朝华相顾,愿你前程似锦。