代理模式:当需要调用某个对象的时候,不需要关心拿到的是不是一定是这个对象,它需要的是,我拿到的这个对象能够完成我想要让它完成的任务即可,也就是说,这时调用方可以拿到一个代理的一个对象,这个对象可以调用它想创建的对象的方法完成调用方的任务就好了。
应用场景介绍:这里有一个PDF,我想打开,但是,初始化的过程比较耗时,那么在这个时候如果在创建对象的时候直接初始化那么势必会消耗掉一定的时间,但是并不一定初始化完成以后就直接要打开,可能过一段时间之后才需要打开呢,是有可能的。
File的一个接口,这个接口定义了一个openFile的方法。
package com.siti.proxytest1;
public interface File {
/**
* 打开文件
*/
public void openFile();
}
PDFFile实现File接口,并实现openFile方法。
package com.siti.proxytest1;
public class PDFFile implements File{
/**
* sleep一秒钟表示初始化的时候的耗时
*/
public PDFFile(){
try {
Thread.sleep(1000);
System.out.println("PDF文件加载成功~");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void openFile() {
System.out.println("PDF文件打开!");
}
}
package com.siti.proxytest1;
public class PDFFileProxy implements File{
private PDFFile pdfFile;
/**
* 获取代理对象
* @param pdfFile
*/
public PDFFileProxy(PDFFile pdfFile){
this.pdfFile = pdfFile;
}
/**
* 代理对象调用openFile方法时,才会创建pdfFile对象(耗时1s);
* 然后执行对象的openFile方法完成。
*/
@Override
public void openFile() {
if(pdfFile == null){
this.pdfFile = new PDFFile();
}
pdfFile.openFile();
}
}
package com.siti.proxytest1;
public class ProxyTest {
public static void main(String[] args) {
Long beginTime = System.currentTimeMillis();
// 创建代理对象
PDFFileProxy proxy = new PDFFileProxy(null);
Long MiddTime = System.currentTimeMillis();
System.out.println("创建代理对象耗时:" + (MiddTime - beginTime));
// 调用openFile方法,创建实际的PDFFile对象并执行openFile方法
// 如果此时不调用openFile的话那么这一秒钟的时间就会被节约下来,那么只是消耗了创建代理对象的时间(很少的时间)
proxy.openFile();
System.out.println("打开文件耗时:" + (System.currentTimeMillis() - beginTime));
}
}
当然,系统的最终开销并没有减少,但是有的时候创建完对象之后并不一定就会直接调用它的方法,甚至直到被回收也没有调用,那么这时候代理模式很显然的效率更高,再者就是推迟了对象的创建时间,保障前面的程序运行流畅的,减少对象在内存中的存活时间,宏观上减少了内存的消耗。
Hibernate默认使用延迟加载(懒加载),也就是,当一个对象关联着另一个对象的时候,默认是不被直接加载的,它会获得一个代理对象,等到真正调用的时候,这个对象才真正的被创建。
借用上面类似的例子
首先还是一个File接口:
package com.siti.proxytest2;
public interface File {
/**
* 加载文件
*/
public void loadFile();
/**
* 打开文件
*/
public void openFile();
}
package com.siti.proxytest2;
public class PDFFile implements File{
@Override
public void openFile() {
System.out.println("PDF文件打开!");
}
@Override
public void loadFile() {
System.out.println("PDF文件加载成功~");
}
}
package com.siti.proxytest2;
public class TransactionManager {
/**
* 事务开启
*/
public void transactionStart(){
System.out.println("事务开启!");
}
/**
* 事务关闭
*/
public void transactionEnd(){
System.out.println("事务关闭!");
}
}
package com.siti.proxytest2;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class MyInvocationHandler implements InvocationHandler {
// 需要被代理的对象
private Object targetObj;
public void setProxyObj(Object targetObj){
this.targetObj = targetObj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
TransactionManager transaction = new TransactionManager();
transaction.transactionStart();
// 执行targetObj的method方法
Object obj = method.invoke(targetObj, args);
transaction.transactionEnd();
return obj;
}
}
package com.siti.proxytest2;
import java.lang.reflect.Proxy;
public class ProxyFactory {
public static Object getProxy(Object targetObj) {
// 创建一个MyInvocationHandler
MyInvocationHandler handler = new MyInvocationHandler();
// 为MyInvocationHandler设置target对象
handler.setProxyObj(targetObj);
// 返回一个动态代理对象
return Proxy.newProxyInstance(targetObj.getClass().getClassLoader(),
targetObj.getClass().getInterfaces(), handler);
}
}
测试类如下:
package com.siti.proxytest2;
import com.siti.proxytest2.PDFFile;
public class ProxyTest {
public static void main(String[] args) {
File pdfFileTarget = new PDFFile();
// 创建动态代理
File pdfFile = (File) ProxyFactory.getProxy(pdfFileTarget);
pdfFile.loadFile();
pdfFile.openFile();
}
}
运行结果:
动态代理可以灵活地实现解耦,这种方式可以为对象提供附加的功能。
原文:http://blog.csdn.net/wangyang1354/article/details/50726262