何为代理,代理概念可以解释为:在出发点到目的地之间有一道中间层,意为代理。何为代理模式,为其他对象提供一种代理以控制对这个对象的访问。
三要素
- Subject抽象主题角色。可以是抽象类,也可以是接口
- RealSubject。具体主题角色,也就是被代理角色
- Proxy代理主题角色。也叫做为委托类,代理类。它负责对真实主题的调用,把所有抽象主题类定义的方法委托给真实主题角色的实现,并且在真实主题角色处理完毕后前后做预处理和善后工作。
反例
下面的示例中,以实现一个简单的计算器为例,这个计算可以计算加法和减法,并且将结果进行输出
先定义一个计算器接口:
/**
* @author:xiapeng
* @description:计算器接口(Subject抽象主题角色)
* @date: 2018-10-22 11:06
* @version: 1.0
*/
public interface Calculator {
int add(int x, int y);
int sub(int x, int y);
}
计算器实现类
/**
* CalculatorImpl
*
* @author xiapeng
* @version 1.0
* @description 计算器实现类
* @date 2018-10-22 11:07
*/
public class CalculatorImpl implements Calculator {
@Override
public int add(int x, int y) {
int c = x + y;
System.out.println("add方法结果为:" + c);
return c;
}
@Override
public int sub(int x, int y) {
int c = x - y;
System.out.println("sub方法结果为:" + c);
return c;
}
}
client类:
/**
* Client
*
* @author xiapeng
* @version 1.0
* @description 客户端计算
* @date 2018-10-22 11:12
*/
public class Client {
public static void main(String[] args) {
Calculator calculator = new CalculatorImpl();
calculator.add(10, 6);
System.out.println("--------------------------------------------------------------------");
calculator.sub(10, 6);
}
}
以上做法是不推荐的,如果计算以后新增了一个乘法除法,也需要记录日志,是不是也得在具体实现方法里面加上日志代码呐?接下来介绍使用动态代理来实现该功能
示例
计算器实现类:
/**
* CalculatorImpl
*
* @author xiapeng
* @version 1.0
* @description 计算器实现类(RealSubject)
* @date 2018-10-22 11:07
*/
public class CalculatorImpl implements Calculator {
@Override
public int add(int x, int y) {
int c = x + y;
return c;
}
@Override
public int sub(int x, int y) {
int c = x - y;
return c;
}
}
日志处理类:
/**
* LoggingHandler
*
* @author xiapeng
* @version 1.0
* @description 日志处理(Proxy代理主题角色)
* @date 2018-10-22 11:10
*/
public class LoggingHandler implements InvocationHandler {
private Calculator calculator;
public LoggingHandler(Calculator calculator) {
this.calculator = calculator;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = method.invoke(calculator, args);
System.out.println(method.getName() + "方法结果为:" + result);
return result;
}
}
客户端:
/**
* Client
*
* @author xiapeng
* @version 1.0
* @description 客户端计算
* @date 2018-10-22 11:12
*/
public class Client {
public static void main(String[] args) {
Calculator calculator = new CalculatorImpl();
Calculator proxiedCalculator = (Calculator) Proxy.newProxyInstance(
calculator.getClass().getClassLoader(),
calculator.getClass().getInterfaces(),
new LoggingHandler(calculator)
);
proxiedCalculator.add(10, 6);
System.out.println("--------------------------------------------------------------------");
proxiedCalculator.sub(10, 6);
}
}
相比反例中的代码,这段代码的好处就是如果计算器增加了计算方法,如乘法,除法,记录日志时,不需要耦合到具体实现类,换言之,不需要为加减乘除的每个方法里面增加日志代码,而在Proxy代理主题角色(LoggingHandler.java)进行处理。
优点
- 职责清晰。真实的角色就只是实现业务逻辑,不用关心其他事务。
- 高扩展性。RealSubject(具体主题实现)无论如何变化,只要他实现了Subject(抽象主题)的接口,都可以被代理。