代理模式与Java动态代理

 

一、代理模式

代理模式(Proxy Pattern):为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

图一:代理模式

为了保持行为的一致性,代理类和委托类通常会实现相同的接口,所以在访问者看来两者没有丝毫的区别。通过代理类这中间一层,能有效控制对委托类对象的直接访问,也可以很好地隐藏和保护委托类对象,同时也为实施不同控制策略预留了空间,从而在设计上获得了更大的灵活性。

为了理解的更具体,举个例子说明一下吧。代理模式最经典的例子,那就是销售代理。假如你要买一台联想笔记本电脑(支持国产,本屌一直用联想的本本),现在有两个选择:方案一是去联想的生产工厂买,方案二是到当地的数码城去买。应该绝大多数都是选择方案二,除非你家就在联想工厂的旁边(你就要一台,还不一定卖给你)。直接找联想买,可能要去上海北京某个分公司,路途遥远浪费路费不说,还需要很多时间。而直接在当地的代理商那买就简单了,数码城、旗舰店到处都是,你还可以货比三家,选择一家优惠又送礼的店。这就是代理的好处,给客户省去很多麻烦,每逢佳节还搞个优惠活动。虽然你的电脑是从代理商那买的,但是代理商最终还要去商家提货的,代理只是做了一些前后的包装工作。就这个例子,我们用代码实现一下。

 

//联想公司
interface LenovoCompany{
	public void sellComputer();
}
//电脑生产厂商
class ComputerMaker implements LenovoCompany{

	@Override
	public void sellComputer() {
		System.out.println("售出一部笔记本电脑...");
	}
}
//代理销售店
class SellProxy implements LenovoCompany{
	
	@Override
	public void sellComputer() {
		
		preconsult();
		//代理要去厂家提货
		new ComputerMaker().sellComputer();
		giveMouse();
	}
	
	public void preconsult(){
		System.out.println("售前咨询。。。");
	}
	public void giveMouse(){
		System.out.println("赠送鼠标一个。。。");
	}
}
//客户购买联想电脑
public class ProxyDemo {
	public static void main(String[] args) {
		LenovoCompany lenovo=new SellProxy();
		lenovo.sellComputer();
	}
}

 


 

 

联想公司就一个目的——买电脑,所以无论是生产厂家还是代理商都必须实现sellComputer()这个根本目的。客户找代理商买电脑,代理提供友好的售前咨询,买电脑还送了鼠标,开开心心带走电脑。客户不需要知道中间经历了什么过程。代理类对客户提供了与主题类ComputerMaker一样的接口sellComputer,代理类可以再在客户真正访问sellComputer前后加以修饰或者控制。

二、动态代理

联想不仅卖电脑还卖智能手机、智能电视、服务端等很多产品,现在都需要在代理商出售前提供售前咨询服务,还要搞活动送礼品来刺激消费。这样代理类中的每个方法都需要和sellCumputer()同样的包装,是不是很麻烦,需要很多重复的代码。幸运的是,Java给我提供了动态代理的技术,动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java 反射机制可以生成任意类型的动态代理类。java.lang.reflect 包中的Proxy类和InvocationHandler 接口提供了生成动态代理类的能力。 现在把上面的例子用动态代理来实现,为了体现动态代理的优势另外还增加了sellMobilePhone()方法。

 

public class DynamicProxy{
	public static void main(String[] args) {
		
		//
		LenovoCompany sell=(LenovoCompany)Proxy.newProxyInstance(LenovoCompany.class.getClassLoader(),
				new Class[]{LenovoCompany.class},new IHImpl());
		
		sell.sellComputer();
		sell.sellMobilePhone();
	}
	
}
//
class IHImpl implements InvocationHandler{
	
	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		preconsult();
		//调用真实实现类
		method.invoke(new ComputerMaker(),args);
		giveMouse();
		return null;
	}
	
	public void preconsult(){
		System.out.println("售前咨询。。。");
	}
	public void giveMouse(){
		System.out.println("赠送礼品。。。");
	}
	
}

现在无论你有多少sellXxx()方法,在调用前后都会自动分别加上preconsult()和giveMouse(),这个神奇的代理是怎么实现的?这里需要一个Proxy类和一个InvocationHandler接口。Proxy类用来自动生成代理类,先来看一下获取代理类的方法public Object newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h);

 

loader:定义代理类的类加载器,一般用接口的加载器就行。

interfaces:代理类要实现的接口列表。

h:方法的处理程序。

InvocationHandler:这是调用处理器接口,它自定义了一个 invoke 方法,用于集中处理在动态代理类对象上的方法调用,通常在该方法中实现对委托类的代理访问。

调用代理类中的方法时,内部会自动调用InvocationHandler实现类中的invoke()方法,需要给invoke提供主题接口的具体实现了实例,调用的方法的Method对象和该方法的参数列表。这样就可以在invoke中调用真是实现类的同名方法了。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值