概念和作用
代理模式是一种结构型设计模式,它允许为其他对象提供一种代理以控制对这个对象的访问。代理对象在客户端和目标对象之间起到中介作用,可以在目标对象执行某些操作前后添加额外的功能。
使用场景
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("老师正在授课"); } }
复制
// 动态代理类 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(); } }
复制
优点和缺点
优点
1.职责分离:将核心业务逻辑与附加功能分离,符合单一职责原则。
2.增强功能:可以在不修改目标对象代码的情况下增强其功能。
3.灵活扩展:动态代理可以在运行时为不同目标对象生成代理,具有很高的灵活性。
缺点
1.性能开销:代理模式会增加一定的性能开销,尤其是动态代理。
2.代码复杂度增加:需要额外编写代理类代码,增加了系统的复杂度。
不使用代理模式
如果不使用代理模式,我们可能需要直接在目标对象的方法中添加额外的功能,或者通过继承目标类并重写方法来实现。例如:
public class EnhancedTeacher extends Teacher { @Override public void teach() { // 前置操作 System.out.println("开始上课前的准备工作"); super.teach(); // 后置操作 System.out.println("课程结束,安排课后作业"); } }
复制
这种方式虽然简单,但存在以下问题:
1.侵入性修改:需要修改目标类的代码或继承目标类,违反了开闭原则。
2.复用性差:如果多个目标类需要相同的附加功能,需要重复编写代码。
3.耦合度高:客户端直接依赖具体的增强类,不利于系统的扩展和维护。
综上所述,代理模式是一种非常实用的设计模式,在需要增强对象功能、控制对象访问等场景下具有广泛的应用价值。