目录
现实例子
什么是代理模式?举个例子来说明:假如说我现在想买一辆二手车,虽然我可以自己去找车源,做质量检测等一系列的车辆过户流程,但是这确实太浪费我得时间和精力了。我只是想买一辆车而已为什么我还要额外做这么多事呢?于是我就通过中介公司来买车车,他们来给我找车源,帮我办理车辆过户流程,我只是负责选择自己喜欢的车,然后付钱就可以了。
再比如打官司, 为什么要找个律师? 因为你不想参与中间过程的是是非非, 只要完成自己的答辩就成, 其他的事前调查、事后追查等都由律师来搞定, 这就是为了减轻你的负担。
概念
为其他对象提供一种代理,以控制对这个对象的访问。代理对象在客户端和目标对象之间起到中介的作用。
使用场景
1、限制目标对象。
2、保护目标对象。
3、增强目标对象。
作用和意义
1、中介隔离作用
在某些情况下,一个客户类不想或者不能直接引用一个委托对象,而代理类对象可以在客户类和委托对象之间起到中介的作用,其特征是代理类和委托类实现相同的接口。
2、开闭原则,增加功能
代理类除了是客户类和委托类的中介之外,我们还可以通过给代理类增加额外的功能来扩展委托类的功能,这样做我们只需要修改代理类而不需要再修改委托类,符合代码设计的开闭原则。
代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后对返回结果的处理等。代理类本身并不真正实现服务,而是同过调用委托类的相关方法,来提供特定的服务。真正的业务功能还是由委托类来实现,但是可以在业务功能执行的前后加入一些公共的服务。例如我们想给项目加入缓存、日志这些功能,我们就可以使用代理类来完成,而没必要打开已经封装好的委托类。
优缺点
优点
1、代理模式能将代理对象与真实对象被调用的目标对象分离。
2、一定程度上降低了系统的耦合度,扩展性好。
3、保护目标对象。
4、增强目标对象。
缺点
1、代理模式会造成系统设计中类的数目的增加。
2、在客户端和目标对象增加一个代理对象,会造成请求处理速度变慢。
3、增加了系统的复杂度。
UML结构图
角色构成
抽象主题(Subject)类
通过接口或抽象类声明真实主题和代理对象实现的业务方法。
真实主题(Real Subject)类
实现了抽象主题中的具体业务,是代理对象所代表的真实对象,是最终要引用的对象。
代理(Proxy)类
提供了与真实主题相同的接口,其内部含有对真实主题的引用,它可以访问、控制或扩展真实主题的功能。
代理模式的种类
按照代理创建的时期来进行分类的话:可以分为两种:静态代理、动态代理。
静态代理
定义
代理类在编译期就生成。
优点
可以做到在符合开闭原则的情况下对目标对象进行功能扩展。
缺点
我们得为每一个服务都得创建代理类,工作量太大,不易管理。同时接口一旦发生改变,代理类也得相应修改。
动态代理
定义
代理类在程序运行时,运用反射机制动态创建而成。
小结
虽然相对于静态代理,动态代理大大减少了我们的开发任务,同时减少了对业务接口的依赖,降低了耦合度。但是还是有一点点小小的遗憾之处,那就是它始终无法摆脱仅支持interface代理的桎梏。
静态代理和动态代理区别和联系
共同点
两种代理模式实现都在不改动基础对象的前提下,对基础对象进行访问控制和扩展,符合开闭原则。
不同点
静态代理在程序规模稍大时,重复性和脆弱性的缺点凸显;动态代理(搭配泛型参数)实现了一个代理同时处理N多个基础接口,本质上是代理类和基础接口的解耦,一定程度上规避了静态代理的缺点。
从原理上讲,静态代理的代理类Class文件在编译期生成,而动态代理的代理类Class文件在运行时生成,代理类在编译阶段并不存在,代理关系直到运行时才确定。
代码实现
静态代理
ILogger.java
package pattern.proxy.staticproxy;
/**
* <一句话功能简述>代理模式:静态代理模式:抽象主题角色<br/>
* <p>
* <功能详细描述>创建一个代理类和真实类的共同接口ILogger
*
* @author 刘斌
* @date 2020/3/7
* @see [相关类/方法](可选)
* @since [产品/模块版本] (可选)
*/
public interface ILogger {
/**
* 功能描述: 打印日志<br>
*
* @author 刘斌
* @date 2020/3/7 20:00
* @see [相关类/方法](可选)
* @since [产品/模块版本](可选)
*/
void printMessage();
}
RealLog.java
package pattern.proxy.staticproxy;
/**
* <一句话功能简述>代理模式:静态代理模式:真实主题角色<br/>
* <p>
* <功能详细描述>被代理类,现在想要在不改动被代理类代码的前提下,实现对printMessage()方法前后进行操作
*
* @author 刘斌
* @date 2020/3/7
* @see [相关类/方法](可选)
* @since [产品/模块版本] (可选)
*/
public class RealLog implements ILogger {
public RealLog() {
}
@Override
public void printMessage() {
System.out.println("打印日志");
}
}
LogProxy.java
package pattern.proxy.staticproxy;
/**
* <一句话功能简述>代理模式:静态代理模式:代理类角色<br/>
* <p>
* <功能详细描述>被代理类,现在想要在不改动被代理类代码的前提下,实现对printMessage()方法前后进行操作
*
* @author 刘斌
* @date 2020/3/7
* @see [相关类/方法](可选)
* @since [产品/模块版本] (可选)
*/
public class LogProxy implements ILogger {
// 定义一个被代理类的对象
private RealLog log;
public LogProxy() {
}
// 这个构造器传入的是一个接口的对象
public LogProxy(RealLog realLog) {
this.log = realLog;
}
// 代理代理打印日志信息
@Override
public void printMessage() {
preGive();
if (null == log) {
log = new RealLog();
}
log.printMessage();
postGive();
}
public void preGive() {
System.out.println("Before:在printMessage之前进行一些操作");
}
public void postGive() {
System.out.println("After:在printMessage之后进行一些操作");
}
}
StaticProxyClient.java
package pattern.proxy.staticproxy;
/**
* <一句话功能简述>代理模式:静态代理模式:客户端调用<br/>
* <p>
* <功能详细描述>现在想要在不改动被代理类代码的前提下,实现对printMessage()方法前后进行操作
*
* @author 刘斌
* @date 2020/3/7
* @see [相关类/方法](可选)
* @since [产品/模块版本] (可选)
*/
public class StaticProxyClient {
public static void main(String[] args) {
ILogger log = new LogProxy();
log.printMessage();
}
}
静态代理控制台输出
动态代理
LogUtils.java(只是工具类)
package utils;
import java.lang.reflect.Method;
import java.util.Arrays;
/**
* <一句话功能简述>日志打印工具类<br/>
* <p>
* <功能详细描述>
*
* @author 刘斌
* @date 2020/3/7
* @see [相关类/方法](可选)
* @since [产品/模块版本] (可选)
*/
public class LogUtils {
public static void startLog(Method method, Object... objects) {
System.out.println("【" + method.getName() + "】执行开始了,他的参数为【" + Arrays.asList(objects) + "】");
}
public static void endLog(Method method, Object... objects) {
System.out.println("【" + method.getName() + "】执行结束了,他的结果为【" + Arrays.asList(objects) + "】");
}
public static void exceptionLog(Method method, Exception e) {
System.out.println("【" + method.getName() + "】执行出错了,错误信息为【" + e.getCause() + "】");
}
public static void finallyLog(Method method) {
System.out.println("【" + method.getName() + "】最终执行结束了");
}
}
ICalculator.java
package pattern.proxy.dynamicproxy;
/**
* <一句话功能简述>代理模式:动态代理模式:抽象主题角色<br/>
* <p>
* <功能详细描述>创定义一个计算机接口
*
* @author 刘斌
* @date 2020/3/7
* @see [相关类/方法](可选)
* @since [产品/模块版本] (可选)
*/
public interface ICalculator {
public int add(int num1, int mu2);
public int sub(int num1, int mu2);
public int mul(int num1, int mu2);
public int div(int num1, int mu2);
}
MyCalculatorImpl.java
package pattern.proxy.dynamicproxy;
/**
* <一句话功能简述>代理模式:动态代理模式:真实主题角色<br/>
* <p>
* <功能详细描述>被代理类
*
* @author 刘斌
* @date 2020/3/7
* @see [相关类/方法](可选)
* @since [产品/模块版本] (可选)
*/
public class MyCalculatorImpl implements ICalculator {
@Override
public int add(int i, int j) {
//手动为方法添加日志
//LogUtils.startLog(i,j,"加法");
int result;
result = i + j;
return result;
}
@Override
public int sub(int i, int j) {
int result;
result = i - j;
return result;
}
@Override
public int mul(int i, int j) {
int result;
result = i * j;
return result;
}
@Override
public int div(int i, int j) {
int result;
result = i / j;
return result;
}
}
CalculatorProxy.java
package pattern.proxy.dynamicproxy;
import utils.LogUtils;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* <一句话功能简述>代理模式:动态代理模式:代理类角色<br/>
* <p>
* <功能详细描述>被代理类,现在想要在不改动被代理类代码的前提下,实现功能的扩展
*
* @author 刘斌
* @date 2020/3/7
* @see [相关类/方法](可选)
* @since [产品/模块版本] (可选)
*/
public class CalculatorProxy {
public static ICalculator getPoxy(ICalculator myCalcultor) {
//为执行Proxy.newProxyInstance(loader, interfaces, h),三个参数赋值
ClassLoader classLoader = myCalcultor.getClass().getClassLoader();
Class<?>[] interfaces = myCalcultor.getClass().getInterfaces();
InvocationHandler invocationHandler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//对原方法添加日志
Object result = null;
try {
LogUtils.startLog(method, args);
result = method.invoke(myCalcultor, args);
LogUtils.endLog(method, result);
} catch (Exception e) {
LogUtils.exceptionLog(method, e);
} finally {
LogUtils.finallyLog(method);
}
return result;
}
};
//生成代理对象
ICalculator proxy = (ICalculator) Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
return proxy;
}
}
DynamicProxyClient.java
package pattern.proxy.dynamicproxy;
/**
* <一句话功能简述>代理模式:动态代理模式:客户端调用<br/>
* <p>
* <功能详细描述>
*
* @author 刘斌
* @date 2020/3/7
* @see [相关类/方法](可选)
* @since [产品/模块版本] (可选)
*/
public class DynamicProxyClient {
public static void main(String[] args) {
originCalc();
}
public static void originCalc() {
ICalculator myCalculator = new MyCalculatorImpl();
//int result=myCalculator.add(2, 4);
//采用动态代理为方法添加日志
ICalculator proxy = CalculatorProxy.getPoxy(myCalculator);
proxy.add(2, 4);
proxy.div(2, 1);
}
}
动态代理控制台输出