Java设计模式--代理模式

1. 代理模式的引入

王大爷借了小李1.5亿,小赖是个无赖横竖就是不还钱,王大爷身子弱讨不回钱就请了讨债公司的小强,最后小强通过一系列**(过于残暴被打码了)的手段帮助王大爷讨回欠款。完事后还帮王大爷做了封口的工作。这个场景中,小强就是一个代理的存在。

2. 静态代理模式的实现

package test;

public class TsetProxy {
	public static void main(String[] args) {
		ProxySubject proxySubject = new ProxySubject(new RealSubjest());
		proxySubject.getDebt();
	}
}

interface Subject{
	public void getDebt();//讨债
}

class RealSubjest implements Subject{
	@Override
	public void getDebt() {  
		// 王大爷讨债
		System.out.println("王大爷讨回1.5亿欠款");
	}
}

//代理讨债
class ProxySubject implements Subject{
	private Subject realSubject ;
	public ProxySubject(Subject subject) {
		this.realSubject = subject;
	}
	public void prepare() {
		System.out.println("讨债前的准备工作...威胁、恐吓、外加毒打一顿....");
	}
	@Override
	public void getDebt() {
		this.prepare();
		this.realSubject.getDebt();
		this.destory();
	}
	public void destory() {
		System.out.println("讨债后的清理工作....杀人灭口、毁尸灭迹......");
	}
}

剧情的发展好像有点脱离控制了。为什么讨完债要杀人灭口,毁尸灭迹呢?这不是重点。

重点是!!!

代理类调用了核心类的接口对象,完成了核心类的方法。其实上面的过程就像一个“汉堡包”,现在看来可能比较像“三明治”。看到后面,你会发现代理模式其实是一个“汉堡包”。

 

3. 静态代理模式的优化

上面的代码虽然简单,但是分层结构不清晰,改进如下:

package Service;
public interface IDebtService {
	public void getDebt() ;
}
package Service;
public class DebtServiceImpl implements IDebtService{
	@Override
	public void getDebt() {
		System.out.println("王大爷讨回1.5亿欠款.......");
	}
}
package Manager;
public interface IDebtManager {
	//讨债前准备工作
	public void brefore();
	//讨债后清理工作
	public void after();
}
package Manager;
public class DebtManagerImpl implements IDebtManager{
	@Override
	public void brefore() {
		System.out.println("讨债前的准备工作:威胁、恐吓、外加毒打一顿....");	
	}

	@Override
	public void after() {
		System.out.println("讨债后的清理工作:杀人灭口、毁尸灭迹......");
	}
}
package Proxy;
import Manager.IDebtManager;
import Service.IDebtService;

public class DebtStaticProxyImpl implements IDebtService{
	private IDebtManager proxy; //代理对象
	private IDebtService target;  //核心对象
	
	public DebtStaticProxyImpl(IDebtManager proxy, IDebtService target) {
		this.proxy = proxy;
		this.target = target;
	}

	@Override
	public void getDebt() {
		proxy.brefore();  //前期工作
		target.getDebt();  //讨债过程
		proxy.after();  //后期工作
	}

}

测试类:

import Manager.DebtManagerImpl;
import Manager.IDebtManager;
import Proxy.DebtStaticProxyImpl;
import Service.DebtServiceImpl;
import Service.IDebtService;
public class Main {
	public static void main(String[] args) {
		//准备一个王大爷对象
		IDebtService target = new DebtServiceImpl();
		//准备一个代理对象
		IDebtManager proxy = new DebtManagerImpl();
		//代理程序
		IDebtService debtService = new DebtStaticProxyImpl(proxy, target);
		debtService.getDebt();
	}
}

运行结果:

讨债前的准备工作:威胁、恐吓、外加毒打一顿....
王大爷讨回1.5亿欠款.......
讨债后的清理工作:杀人灭口、毁尸灭迹......

讨债公司也并没有这么简单,既然帮王大爷讨债,那总不能白讨是吧,这讨债费这么算得事先说得明明白白,事后算得清清楚楚才行。于是来了财务小钱(另一个代理),负责处理这个过程的讨债费用问题。

财务代理类:

package Manager;
public class DebtFeeManagerImpl implements IDebtManager{
	@Override
	public void brefore() {
		System.out.println("讨债前财务工作:拟定讨债费用合同,监督双方签字..........");
	}

	@Override
	public void after() {
		System.out.println("讨债后财务工作:清算讨债费用,帮助双方完成讨债费交付..........");
	}
}

测试类:

import Manager.DebtFeeManagerImpl;
import Manager.DebtManagerImpl;
import Manager.IDebtManager;
import Proxy.DebtStaticProxyImpl;
import Service.DebtServiceImpl;
import Service.IDebtService;

public class Main {
	public static void main(String[] args) {
		//准备一个王大爷对象
		IDebtService target = new DebtServiceImpl();
		//准备一个代理对象
		IDebtManager proxy = new DebtManagerImpl();
		//准备一个财务代理
		IDebtManager proxy2 = new DebtFeeManagerImpl();
		//代理程序
		IDebtService debtService = new DebtStaticProxyImpl(proxy, target);//讨债
		debtService = new DebtStaticProxyImpl(proxy2, debtService);//财务清算
		debtService.getDebt();
	}
}

运行结果:

讨债前财务工作:拟定讨债费用合同,监督双方签字..........
讨债前的准备工作:威胁、恐吓、外加毒打一顿....
王大爷讨回1.5亿欠款.......
讨债后的清理工作:杀人灭口、毁尸灭迹......
讨债后财务工作:清算讨债费用,帮助双方完成讨债费交付..........

但是现在的程序是有缺点的。第一点是proxy继承了核心类,这就导致了Service层每增加一个接口类,Proxy层就要对应增加一个新的类,但是这些proxy类的完成的事情是一致的,就是将核心类和代理类编织在一起。第二点就是静态代理内部的实现跟Service接口的具体方法耦合在一起了,一旦改动接口的方法名称(当然一般不会这么做),静态代理类也得跟着改。

4. 动态代理的实现

静态代理是在编译时就生成代理对象,而动态代理是运行期才生产代理对象。

动态代理有两种:“JDK动态代理”和“CGLIB动态代理”

4.1 JDK动态代理

关键类:java.lang.reflect.InvocationHandler(编织器)和java.lang.reflect.Proxy

程序实现:在上一个工程的基础上把DebtStaticProxyImpl干掉,然后写一个DynamicProxyHandler类

package Proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import Manager.IDebtManager;
public class DynamicProxyHandler implements InvocationHandler{
	private Object target; //核心类
	private IDebtManager iDebtManager; //代理类
	
	public DynamicProxyHandler(Object target, IDebtManager iDebtManager) {
		this.target = target;
		this.iDebtManager = iDebtManager;
	}
	
	/**
	 * proxy:代理类
	 * method:被调用的核心方法
	 * args:核心方法的参数
	 */
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		iDebtManager.brefore();
		Object res = method.invoke(target, args);
		iDebtManager.after();
		return res;
	}
}

测试类:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import Manager.DebtManagerImpl;
import Manager.IDebtManager;
import Proxy.DynamicProxyHandler;
import Service.DebtServiceImpl;
import Service.IDebtService;

public class Main {
	public static void main(String[] args) {
		//准备一个王大爷对象
		IDebtService target = new DebtServiceImpl();
		//准备一个代理对象
		IDebtManager proxy = new DebtManagerImpl();
		//准备一个Handler(编织器)
		InvocationHandler handler = new DynamicProxyHandler(target, proxy);
		//代理程序
		IDebtService iDebtService = (IDebtService)Proxy.newProxyInstance(target.getClass().getClassLoader(), 
				target.getClass().getInterfaces(), 
				handler);
		iDebtService.getDebt();
	}
}

4.2 CGLIB动态代理

JDK动态代理有个局限:只适用于面向接口编程。对于没有接口的类,如何实现动态代理呢,这就需要CGLib(Code Generation Library)了。

首先,CGLIB是一个第三方的框架,所以需要引入jar包,官方下载地址:https://github.com/cglib/cglib/releases

CGlibHandler:

package Proxy;

import java.lang.reflect.Method;
import Manager.IDebtManager;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

/**
 * MethodInterceptor : 方法拦截器
 * @author luo
 *
 */
public class CGlibHandler implements MethodInterceptor{
	private IDebtManager iDebtManager;

	public CGlibHandler(IDebtManager iDebtManager) {
		this.iDebtManager = iDebtManager;
	}

	@Override
	public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
		// TODO Auto-generated method stub
		iDebtManager.brefore();
		Object res = proxy.invokeSuper(obj, args);
		iDebtManager.after();
		return res;
	}
}

测试类:

import Manager.DebtManagerImpl;
import Manager.IDebtManager;
import Proxy.CGlibHandler;
import Service.DebtServiceImpl;
import Service.IDebtService;
import net.sf.cglib.proxy.Enhancer;

public class Main {
	public static void main(String[] args) {
		//准备一个王大爷对象
		IDebtService target = new DebtServiceImpl();
		//准备一个代理对象
		IDebtManager proxy = new DebtManagerImpl();
		//准备一个Handler(编织器)
		CGlibHandler handler = new CGlibHandler(proxy);
		//代理程序
		Enhancer enhancer = new Enhancer(); //通过cglib生成目标对象的子类来动态创建代理对象
		enhancer.setSuperclass(target.getClass());//设置父类
		enhancer.setCallback(handler);//设置处理逻辑
		IDebtService iDebtService = (IDebtService)enhancer.create();
		iDebtService.getDebt();
	}
}

4.3  总结

  CGLIB创建的动态代理对象比JDK创建的动态代理对象的性能更高,但是CGLIB创建代理对象时所花费的时间却比JDK多得多。所以对于单例的对象,因为无需频繁创建对象,用CGLIB合适,反之使用JDK方式要更为合适一些。同时由于CGLib由于是采用动态创建子类的方法,对于final修饰的方法无法进行代理。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值