编程好帮手——代理模式

一,代理模式

1.代理模式的定义

为其他对象提供一个代理,以控制该对象的访问。

2.代理模式的使用场景

总而言之,只要客户端代码不能或不想直接访问被调用对象——这种情况有很多原因,比如需要创建一个系统开销很大的对象,或者被调用对象在远程主机上,或者目标对象的功能还不足以满足需求…而是额外创建一个代理对象返回给客户端使用,那么这种设计方式就是代理模式。

3.代理模式的UML类图

在这里插入图片描述

4.代理模式的实现

/**
 * Image接口,代表大图片对象所实现的接口
 * @author Administrator
 *
 */
public interface Image {
	void show();
}
/**
 * BigImage模拟一个很大的图片
 * @author Administrator
 *
 */
public class BigImage implements Image{
	public BigImage() {
		try {
			//程序暂停3秒模拟系统开销
			Thread.sleep(3000);
			System.out.println("图片装载成功!");
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	//实现Image里的show方法
	@Override
	public void show() {
		// TODO Auto-generated method stub
		System.out.println("绘制实际的大图片");
	}

}
public class ImageProxy implements Image{
	//组合一个image对象,作为被代理的对象
	private Image image;
	//使用抽象实体来初始化代理对象
	public ImageProxy(Image image) {
		this.image = image;
	}
	/**
	 * 重写Image接口的show方法
	 * 该方法用于控制对被代理对象的访问
	 * 并根据需要负责创建和删除被代理对象
	 */
	@Override
	public void show() {
		// TODO Auto-generated method stub
		//只有当真正需要调用image的show方法时才创建被代理对象
		if(null==image) {
			image = new BigImage();
		}
		image.show();
	}

}
/**
 * 程序入口函数
 * @author Administrator
 *
 */
public class BigImageTest {
	public static void main(String[] args) {
		long start = System.currentTimeMillis();
		//程序返回一个Image对象,该对象只是BigImage的代理对象
		Image image = new ImageProxy(null);
		System.out.println("系统得到Image对象的时间开销:"+
				(System.currentTimeMillis()-start));
		//只有当实际调用image代理的show()方法时,程序才会真正创建被代理对象
		image.show();
	}

}

5.总结

代理模式应用广泛,其他形式的结构型模式中,都可以看到代理模式的影子,有些模式单独作为一种设计模式,倒不如说是对代理模式的一种针对性优化。而且代理模式几乎没有什么缺点而言,它是细分化至很小的一种模式,要真的说一个缺点,那么就是所有设计模式的通病:对类的增加,不过在这种孰优孰劣的局势下,就算对类的稍微增加又何妨呢?

二,动态代理模式

除了上面处于性能考虑使用代理模式外,代理模式还有另一种常用场景:当目标对象的功能不足以满足客户端需求时,系统可以为改对象创建一个代理对象,而代理对象可以增强原目标对象的功能。
借助于Java提供的Proxy和InvocationHandler,可以实现在运行时生成动态代理的功能,而动态代理对象就可作为目标对象使用,而且增强了目标对象的功能。

public interface Dog {
	//info()方法声明
	void info();
	//run()方法声明
	void run();
}
public class GunDog implements Dog {

	@Override
	public void info() {
		// TODO Auto-generated method stub
		System.out.println("我是一只猎狗");
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		System.out.println("我奔跑迅速");
	}

}
public class TxUtil {
	//第一个拦截器方法:模拟事务开始
	public void beginTx() {
		System.out.println("=======模拟事务开始======");
	}
	//第二个拦截器方法:模拟事务结束
	public void endTx() {
		System.out.println("=======模拟事务结束========");
	}
}

JDK动态代理的关键就在于下面的MyInvocationHandler类,该类是一个InvocationHandler实现类,改实现类的invoke方法将会作为代理对象的方法实现。

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class MyInvocationHandler implements InvocationHandler{
	//需要被代理的对象
	private Object target;

	public void setTarget(Object target) {
		this.target = target;
	}

	//执行动态代理对象的所有方法时,都会被替换成执行如下的invoke方法
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		// TODO Auto-generated method stub
		TxUtil tx = new TxUtil();
		//执行TxUtil对象中的beginTx();
		tx.beginTx();
		//以target作为主调来执行method方法
		Object result = method.invoke(target, args);
		//执行TxUtil对象中的endTx().
		tx.endTx();
		return result;
	}
}

下面提供的MyProxyFactory类,该对象专为指定的target生成动态代理实例。

import java.lang.reflect.Proxy;

public class MyProxyFactory {
	//为指定target生成动态代理对象
	public static Object getProxy(Object target)
			throws Exception{
		//创建一个MyInvocationHandler对象
		MyInvocationHandler handler = new MyInvocationHandler();
		//为MyInvocationHandler设置target对象
		handler.setTarget(target);
		//创建并返回一个动态代理
		return Proxy.newProxyInstance(target.getClass().getClassLoader()
				,target.getClass().getInterfaces(), handler);
	}
}
/**
 * 主程序测试动态代理
 * @author Administrator
 *
 */
public class Test {
	public static void main(String[] args) throws Exception{
		//创建一个原始的GunDog对象,作为target
		Dog target = new GunDog();
		//以指定的target来创建动态代理
		Dog dog = (Dog)MyProxyFactory.getProxy(target);
		//调用代理对象的info()和run()方法
		dog.info();
		dog.run();
	}
}

这种动态代理在AOP(Aspect Orient Program,面向切面编程)里被称为AOP代理,AOP代理可代替目标对象,AOP代理包含了目标对象的全部方法。但AOP代理的方法与目标对象的方法存在差异:AOP代理的方法可以在执行目标方法之前、之后插入一些通用处理。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值