参考:http://blog.csdn.net/luanlouis/article/details/24589193
代理模式的原理:
使用一个代理将对象包装起来,然后使用该代理对象取代原始对象。任何对原始对象的调用都要通过代理对象进行,代理对象决定何时以何种方式进行方法调用原始对象和它的方法。
1、定义接口
public interface ArithmeticCalculator {
int add(int i, int j);// 有返回值
int sub(int i, int j);
void mul(int i, int j);// 无返回值
void div(int i, int j);
}
2、定义接口的实现类
public class ArithmeticCalculatorImpl implements ArithmeticCalculator {
@Override
public int add(int i, int j) {
int result = i + j;
return result;
}
@Override
public int sub(int i, int j) {
int result = i - j;
return result;
}
@Override
public void mul(int i, int j) {
int result = i * j;
System.out.println(result);
}
@Override
public void div(int i, int j) {
int result = i / j;
System.out.println(result);
}
}
3、在使用上面的实现类时,当需求出现大量的非核心代码(日志\验证代码\事物),尽量不要在源代码中修改,使用动态代理可以减少代码量。
public class ArithmeticCalculatorTest {
@Test
public void calculatorTest() {
final ArithmeticCalculatorImpl arithmeticCalculatorImpl = new ArithmeticCalculatorImpl();// 创建被代理对象。当然在newProxyInstance()方法中使用其他方法代替而不出现在这里。
/**
* 目的:产生代理对象
* ClassLoader loader 由动态代理产生的对象是由哪个类加载器来加载。通常是和被代理对象使用相同的类加载器。
* Class<?>[] interfaces 动态代理对象必须指定它要代理的接口列表。
* InvocationHandler h 当产生的这个代理对象在调用interfaces接口中的方法时,这个代理对象要产生什么行为。
*/
ArithmeticCalculator proxyInstance = (ArithmeticCalculator) Proxy.newProxyInstance(arithmeticCalculatorImpl.getClass().getClassLoader(),new Class[]{ ArithmeticCalculator.class },new InvocationHandler() {
/**
* proxy:这个是代理对象本身,在invoke方法中可以调用但尽量少用,若使用proxy对象不当,会进行递归调用invoke方法,容易出现StackOverflowError。
* method:代理对象调用目标接口中的对应方法
* args:代理对象传入的参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// System.out.println("method:" + method);//打印代理对象调用目标接口中的对应方法
System.out.println(Arrays.asList(args));//打印代理对象传入的参数
if (method.getName().equals("mul")) {
// 添加前置修饰
System.out.println("1.进行乘法运算");
Object result = method.invoke(arithmeticCalculatorImpl, args);// 指定具体实现类并传入参数
// 添加后置修饰
System.out.println("2.运算结果");
return result;
}
return null;
}
});
/**
* 调用代理对象
*/
proxyInstance.mul(3, 8); // 代理对象调用上面内部类中的invoke的method方法,然后method可以根据这里proxyInstance指定的方法(具体实现类的方法)来调用被代理对象对应的方法。简单点说,使用代理对象调用方法,方法名和实现类的相同,即对象变了,方法名不变。
}
}
4、结果
代理对象传入的参数:[3, 8]
1.进行乘法运算
24
2.运算结果
代理模式的作用是:
为其他对象提供一种代理以控制对这个对象的访问。
在某些情况下,一个客户端不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
代理模式一般涉及到的角色有:
① 抽象角色:声明真实对象和代理对象的共同接口。(真实对象:房主,代理对象:中介,共同接口:完成租房子这件事)
② 代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象可以提供与真实对象相同的接口以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。(房屋中介角色)
③ 真实角色:代理角色所代表的真实对象,是我们最终要引用的对象。(房主角色)
Subject.java类:
package com.baibai.www;
public abstract class Subject {
//抽象角色:声明真实对象和代理对象的共同接口。这是代理角色和真实角色共同拥有的接口。
public abstract void request();
}
RealSubject类:
package com.baibai.www;
public class RealSubject extends Subject {
public void request() {
System.out.println("真实对象亲自来完成了租房这件事");
}
}
ProxySubject类:
package com.baibai.www;
public class ProxySubject extends Subject {
private RealSubject realSubject; // 1.这个引用就是在代理对象角色内部含有对真实对象的引用,从而可以操作真实对象
public void request() { // 2.中介来代理完成租房子这件事
this.preRequest();//4.代理对象可以在执行真实对象操作时,附加其他的操作
if(null==realSubject){
realSubject=new RealSubject();
}
realSubject.request();//3.交给真实角色来完成租房这件事(真正来完成这件事)
this.postRequest();//5.代理对象可以在执行真实对象操作时,附加其他的操作
}
private void preRequest(){
System.out.println("代理角色在真实对象完成之前时做一些其他的事情");
}
private void postRequest(){
System.out.println("代理角色在真实对象完成之后时完成另外一些事情");
}
}