Java设计模式之——代理设计模式

1.什么是代理设计模式

所谓代理模式是指客户端并不直接调用实际的对象,而是通过调用代理,来间接的调用实际的对象。

这里举一个栗子:就拿我们平时租房子来举例子,好比租客和房主之间的关系,我们租房子往往不会挨个去找房东,而是通过中间的代理者,也就是中介完成,租客来间接的和房主接触,这个时候租客(Tenant)相当于用户中介(AgencyProxy)相当于代理者房主(Homeowner)相当于被代理者。

在代理模式种还分为两种模式:静态代理和动态代理,下面我们通过代码来演示以下两种代理方式。

2、静态代理

首先我们先创建一个房主的接口(Houseowner),接口种只有一个租房子的方法。

1 /**
2  * @author wzy
3  * @version 1.0
4  * @date 2019/5/9 15:31
5  */
6 public interface Homeowner {
7     public void letHouse();
8 }

之后我们定义一个类去实现这个接口

 1 /**
 2  * @author wzy
 3  * @version 1.0
 4  * @date 2019/5/9 15:22
 5  */
 6 public class HomeownerImpl implements Homeowner {
 7 
 8     public void letHouse() {
 9         System.out.println("房东:出租了一套房子");
10     }
11 }

房主出租房子一般都会交给中介代理,创建一个AgencyProxy类,我们可以看到下面的类,这个类实现了被Homeowner接口,将房主的实现类作为类的成员变量,并且在自己的letHouse方法中调用目标类的方法,并且可以在调用目标类的前后做一些操作。

 1 public class AgencyProxy implements Homeowner{
 2     //被代理的对象
 3     private HomeownerImpl target;
 4 
 5     public AgencyProxy(HomeownerImpl target) {
 6         this.target = target;
 7     }
 8 
 9     public void letHouse() {
10         System.out.println("中介带租客看房子");
11         target.letHouse();
12         System.out.println("成交后中介收取服务费");
13     }
14 
15 }

接下来,创建一个租客类Tenant进行测试

1 public class Tenant {
2     public static void main(String[] args) {
3         //租房子
4         HomeownerImpl homeowners = new HomeownerImpl();
5         AgencyProxy agencyProxy = new AgencyProxy(homeowners);
6         agencyProxy.letHouse();
7 
8     }
9 }

输出结果:

我们可以看到输出的结果,在调用被代理类的方法前后,代理类都可以做一些操作,这样就可以达到解耦的目的,也可以保护被代理的对象的目的,现在我们思考一下,如果被代理类的方法很多,那么我们每次都要在代理类中将所有方法重写一遍吗?并且如果被代理类中的方法名称发生变化,我们就需要去修改代理类的代码,这显然是不科学的,然而,动态代理就解决了这一问题。

3.动态代理

动态代理分为两种:JDK动态代理和cglib动态代理,动态代理的底层原理是,在程序运行时,通过反射机制动态生成代理类,那么如何实现动态代理呢?我们通过创建一个实现InvocationHandler的类,实现其中的invoke方法,在invoke方法对目标类中的方法进行调用。之后通过Proxy.newProxyInstance()创建一个动态代理的对象。

保持其他代码不动,修改AgencyProxy类的代码:

 1 public class AgencyProxy implements InvocationHandler{
 2     //被代理的对象,目标类
 3     private Homeowner target;
 4     //通过构造函数传入被代理目标类
 5     public AgencyProxy(Homeowner target) {
 6         this.target = target;
 7     }
 8 
 9     public Homeowner getProxy() {
10         //目标类的类加载
11         ClassLoader loader = target.getClass().getClassLoader();
12         //返回代理类的接口列表
13         Class [] classes = target.getClass().getInterfaces();
14         //最后一个参数返回的实现了InvocationHandler的代理类
15         Homeowner homeowner = (Homeowner) Proxy.newProxyInstance(loader, classes, this);
16         //返回代理类对象
17         return  homeowner;
18     }
19 
20     @Override
21     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
22         System.out.println("中介在租房前操作。。。。");
23         //动态执行代理目标类中的方法
24         Object result = method.invoke(target);
25         System.out.println("中介在租房后的操作。。。");
26         return result;
27     }
28 }

修改租客类Tenant测试动态代理:

 1 public class Tenant {
 2     public static void main(String[] args) {
 3         //创建被代理类:房主类
 4         Homeowner homeowners = new HomeownerImpl();
 5         //创建代理类,并传入被代理对象
 6         AgencyProxy agencyProxy = new AgencyProxy(homeowners);
 7         //返回生成的对象
 8         Homeowner homeownerProxy = agencyProxy.getProxy();
 9         //调用方法
10         homeownerProxy.letHouse();
11     }
12 }

输出结果:我们可以看到通过动态代理我们实现了同样的效果。

4.总结

        动态代理是一种十分常用的设计模式,在各种开源框架中都得到了非常广泛的应用,例如Spring的AOP底层就是使用的动态代理,MyBatis底层去代理Mapper使用的也是动态代理,还有就是在日志输出上也会用到这种设计模式,它的优势是实现无侵入式的代码扩展,也就是方法的增强;让你可以在不用修改源码的情况下,增强一些方法;在方法的前后你可以做你任何想做的事情(甚至不去执行这个方法都可以)。

猜你喜欢

转载自www.cnblogs.com/fengyun2019/p/10839200.html