Java设计模式--代理模式【Proxy Pattern】

        什么是代理模式呢?我们大家都知道微商,微商是代理供应商销售产品的一方,简单地说就是代替产品供应商卖产品。关于微商代理,首先我们从他们那里买东西时通常不知道背后的供应商究竟是谁,也就是说,“目标对象”对我们来说是不可见的;其次,微商代理主要以朋友圈的人为目标客户,这就相当于为供应商做了一次对客户群体的“过滤”。我们把微商代理MicroAgent和产品供应商ProductSupplier进一步抽象,前者可抽象为代理类,后者可抽象为委托类(被代理类)。

  代理(Proxy)设计模式的定义:为其他对象提供一种代理以控制对这个对象的访问,即通过代理对象访问目标对象。这样做的好处是既可以隐藏委托类的实现,又可以实现客户与委托类间的解耦,在不修改委托类代码的情况下能够做一些额外的处理。

  

     Java中,代理模式分为静态代理和动态代理两种方式。

  1、静态代理

  若代理类在程序运行前就已经存在,那么这种代理方式被成为静态代理,这种情况下的代理类通常都是我们在Java代码中已经定义的,通常情况下, 静态代理中的代理类和委托类会实现同一接口或是派生自相同的父类。

  下面我们用ProductSupplier类代表产品供应商,MicroAgent类代表微商代理,来介绍下静态代理的简单实现。    

package com.pattern.proxy.v1;
/**
 * 供应商总接口:定义了销售产品的抽象方法
 * @author 
 *
 */
public interface Supplier {
   public void sellProduct();
}
package com.pattern.proxy.v1;
/**
 * 具体的产品供应商:实现了销售产品的方式方法
 * @author 
 *
 */
public class ProductSupplier implements Supplier{
	@Override
	public void sellProduct() {//这才是真的销售产品
		System.out.println("ProductSupplier sell product...");
	}
}
package com.pattern.proxy.v1;
/**
 * 微商代理--只有自己清楚,我不是真正的供应商,只是负责代理销售产品
 * @author 
 *
 */
public class MicroAgent implements Supplier{
	private Supplier supplier;//代理类持有一个委托类对象引用
	
	public MicroAgent() {//默认销售X供应商的产品
		this.supplier = new ProductSupplier();
	}
	public MicroAgent(Supplier supplier) {//也可以销售其他供应商的产品
		this.supplier = supplier;
	}
	
	@Override
	public void sellProduct() {//每天发朋友圈说我这里有产品,你们来买吧
		this.supplier.sellProduct();//实际上是走的通道业务,需要找上级供应商拿货销售
	}
}
客户端测试类:

package com.pattern.proxy.v1;
/**
 * 客户端测试类
 * @author 
 *
 */
public class ClientTest {
   public static void main(String[] args){
	   //顾客看到微商代理的朋友圈,然后说我要买你的产品,
	   //然后微商拿货卖给了顾客,顾客以为产品是微商自己的
	   Supplier agent=new MicroAgent();
	   agent.sellProduct();
   }
}
    从MicroAgent类的定义我们可以看到,静态代理可以通过聚合来实现,让代理类持有一个委托类的引用即可。
2、动态代理

  什么是动态代理?代理类在程序运行时创建的代理方式被成为动态代理。 也就是说,这种情况下,代理类并不是在Java代码中定义的,而是在运行时根据我们在Java代码中的“指示”动态生成的。相比于静态代理, 动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类的函数。 这么说比较抽象,下面我们结合一个实例来介绍一下动态代理的这个优势是怎么体现的。
  现在,假设我们要实现这样一个需求:在执行目标对象的销售产品方法之前需要申请销售额度,在销售完毕后需要及时记录销售额度。我们还是以上面例子中的ProductSupplier类作为委托类,MicroAgent类作为代理类来进行介绍。如果使用静态代理来实现这一需求,需要我们在每个方法中都添加相应的逻辑,这里只存在一个方法所以工作量还不算大,假如Supplier接口中包含上百个方法呢?这时候使用静态代理就会编写许多冗余代码。通过使用动态代理,我们可以做一个“统一指示”,从而对所有代理类的方法进行统一处理,而不用逐一修改每个方法。代码如下:

  首先供应商的接口和产品供应商类,与静态代理中的一致:

package com.pattern.proxy.v2;
/**
 * 供应商总接口:定义了销售产品的抽象方法
 * @author 
 *
 */
public interface Supplier {
   public void sellProduct();
}
package com.pattern.proxy.v2;
/**
 * 具体的产品供应商:实现了销售产品的方式方法
 * @author 
 *
 */
public class ProductSupplier implements Supplier{
	@Override
	public void sellProduct() {
		System.out.println("ProductSupplier sell product...");
	}
}
微商代理类的定义:

package com.pattern.proxy.v2;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
 * 动态代理类只能代理接口(不支持抽象类),代理类都需要实现InvocationHandler类,实现invoke方法。
 * 该invoke方法就是调用被代理接口的所有方法时需要调用的,该invoke方法返回的值是被代理接口的一个实现类  
 * 代理在销售产品前,需要申请产品额度,销售完毕后,需要及时记录产品销售额
 * @author 
 *
 */
public class MicroAgent implements InvocationHandler{
	private Object supplier;//代理类持有一个委托类对象引用

	public MicroAgent() {
	}
	//绑定关系,也就是关联到哪个接口(与具体的实现类绑定)的哪些方法将被调用时,执行invoke方法。 
	public Object newProxyInstance(Object supplierTarget){
		this.supplier=supplierTarget;
		//该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例    
        //第一个参数指定产生代理对象的类加载器,需要将其指定为和目标对象同一个类加载器  
        //第二个参数要实现和目标对象一样的接口,所以只需要拿到目标对象的实现接口  
        //第三个参数表明这些被拦截的方法在被拦截时需要执行哪个InvocationHandler的invoke方法  
        //根据传入的目标返回一个代理对象
		return Proxy.newProxyInstance(Supplier.class.getClassLoader(), new Class[]{Supplier.class}, this);//返回代理类实例 
	}
	@Override
    /*InvocationHandler接口的方法,proxy表示代理,method表示原对象被调用的方法,args表示方法的参数*/  
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		System.out.println("i want 300 products....");//调用前申请产品额
		Object c=method.invoke(supplier, args);//调用目标方法
		System.out.println("i sell 190 products");//调用后记录销售额
		return c;
	}

}
客户端测试类:

package com.pattern.proxy.v2;
/**
 * 客户端测试类
 * @author 
 *
 */
public class ClientTest {
	public static void main(String[] args) {
		MicroAgent handler=new MicroAgent();//通过JDK动态代理获取代理handler
		Supplier proxy=(Supplier)handler.newProxyInstance(new ProductSupplier());//获取代理类的实例对象
		proxy.sellProduct();//代理类销售产品
	}
}
      在代理类代码中,newProxyInstance()方法返回Proxy.newProxyInstance()方法需要3个参数:类加载器ClassLoader(要进行代理的类)、被代理类实现的接口interfaces,事务处理器handler。代理类中,需要传进一个ProductSupplier实例,根据实例和Handler动态生成代理对象,将各参数传入Proxy的静态方法newProxyInstance()即可获得Supplier的代理类。静态代理模式中,代理类是我们编写好的,而动态代理则不需要我们去编写代理类,是在程序中动态生成的。

  总结下来, JDK动态代理步骤如下:

  1. 创建被代理的类及接口:Supplier接口和ProductSupplier类
  2. 创建一个实现InvocationHandler接口的类,它必须实现invoke()方法,上述例子中为MicroAgent类。

  3. 调用Proxy的静态方法,创建一个代理类:Supplier proxy=(Supplier)handler.newProxyInstance(new ProductSupplier());//获取代理类的实例对象

  4. 通过代理调用方法:proxy.sellProduct();//代理类销售产品



源码下载:http://download.csdn.net/download/pelifymeng2/9994734

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值