一、代理模式包含的角色
1、抽象角色:声明真实对象和代理对象的公共接口。
2、代理角色:代理真实对象,实现真实对象想要实现的功能(方法);另外,可附加自身功能(方法)。在代理真实对象的过程中,为了实现代理,应包含一个真实对象的成员变量,通过此成员变量去实例化真实对象,通过实例去调用真实对象的方法,以此来实现对真实对象的调用,实现代理。
3、真实角色:代理角色所代表的真实对象,是我们最终要引用的对象。
可以中介租房的例子来强化理解:
在租房过程中,中介扮演了代理角色,房主代表了真实角色,抽象角色就是把房子租出去。房客只能从中介这里得到房主出租房屋的信息,房主也只能从中介这里得到房客租用房屋的信息。中介在促成房主和房客的交易后,自身会收取一定的中介费,这就是代理对象附加的功能。
二、代理模式的实现
1、静态代理模式
(1)抽象角色
package com.lpp.proxy;
//抽象角色提供真实角色和代理角色的公共接口,这里用抽象类来定义,也可以用接口来定义
public abstract class Subject
{
public abstract void service();
}
(2)真实角色
package com.lpp.proxy;
public class Service extends Subject
{
//真实角色提供最终要实现的方法
public void service()
{
System.out.println("can support a service");
}
}
(3)代理角色
package com.lpp.proxy;
public class ProxyService extends Subject
{
//通过在代理类中引入真实角色的成员变量,借此得到真实角色的实例
private Service service;
private void beforeService()
{
System.out.println("before Service");
}
public void service()
{
this.beforeService();//在代理过程前后可以附加其他代理功能
if(service == null)
{
service = new Service();
}
service.service();
this.afterService();//在代理过程前后可以附加其他代理功能
}
private void afterService()
{
System.out.println("after Service");
}
}
(4)Client端
package com.lpp.proxy;
public class Client
{
//客户端通过代理对象得到真实对象提供的服务
public static void main(String[] args)
{
ProxyService proxyService = new ProxyService();
proxyService.service();
}
}
结果:
before Service
can support a service
after Service
2、动态代理模式
动态类是在运行过程中自动生成的,不是自己定义的。
在静态代理中,一个真实对象中的方法对应一个代理对象,当真实对象中有多个方法时,需要的代理对象也会相应增加,造成类的数量的集聚膨胀。动态代理模式中,一个代理对象可以代理多个真实对象。
动态代理类位于java.lang.reflect包下,一般主要涉及到1个列和1个接口,如下:
(1)接口InvocationHandler
java.lang.reflect
Interface InvocationHandler接口InvocationHandler只有一个方法:Object invoke(Object proxy,Method method, Object[] args) throws Throwable
其中,第一个参数proxy为代理类,第二个参数Method为被代理的方法,第三个参数args为第二个参数Method的参数数组。
(2)类Proxy
- Proxy类中的重要属性和方法
java.lang.reflect
Class Proxy
类Proxy为动态代理类,其定义如下public class Proxy extends Objectimplements Serializable
类Proxy中有一个成员变量(属性)protected InvocationHandler
可见,利用此属性在代理类中可方便引入真实对象中的方法,实现真实对象的功能。
类Proxy的构造函数如下:
protected | Proxy(InvocationHandler h) |
类Proxy中重要的方法有:
public static Class<?> getProxyClass(ClassLoader loader,Class<?>... interfaces) throws IllegalArgumentException
获得一个代理类,第一个参数是一个类装载器,第二个参数是真实类所拥有的全部接口的数组。
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
返回代理类的一个实例,返回后的代理类可以当作被代理类使用(可使用代理类在Subject接口中声明过的所有方法)
- 动态代理的代码编写要点
动态代理对象中通过重写InvocationHandler的invoke()方法,对真实对象中的方法实现调用;Client类中通过使用Proxy类中的newProxyInstance()方法一次性生成代理,此代理又可当作被代理类使用,调用真实对象的方法,完成代理功能。
动态代理的步骤:
1、创建抽象对象、和真实对象:计同静态代理。抽象对象提供代理对象和真实对象的公共接口;真实对象定义代理对象要实现的方法。
2、创建代理对象:创建一个实现几口InvocationHandler的类,然后实现InvocationHandler中的invoke方法。
3、创建代理(Client端):通过Proxy的静态方法
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
创建代理,返回被代理对象(即真实对象),通过返回值调用真实对象的方法,即完成一次动态代理。- 动态代理代码示例
(1)抽象对象(和静态代理差不多)
package com.lpp.proxy;
interface Subject
{
public void service();
}
(2)真实对象(和静态代理完全相同)
package com.lpp.proxy;
public class Service implements Subject
{
public void service()
{
System.out.println("can support a service");
}
}
(3)代理对象(和静态代理不同)
package com.lpp.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class ProxyService implements InvocationHandler
{
private Object sub;
//构造方法
public ProxyService(Object obj)
{
this.sub = obj;
}
private void beforeService()
{
System.out.println("before Service");
}
//重写接口InvocationHandler中的invoke方法
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable
{
this.beforeService();
//调用真实对象中的方法,实现真实对象的功能
method.invoke(sub,args);
this.afterService();
return null;
}
private void afterService()
{
System.out.println("after Service");
}
}
(4)Client类的实现(和静态代理不同)
package com.lpp.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class Client
{
public static void main(String[] args) throws Exception
{
Service service = new Service();
//因为ProxyService类实现了InvocationHandler接口,因此可以利用多态性为InvocationHandler实例化
InvocationHandler handler = new ProxyService(service);
Class<?> classType = handler.getClass();
//一次性生成代理实例,返回结果可作为真实对象使用
Subject subject = (Subject)Proxy.newProxyInstance(classType.getClassLoader(),Service.class.getInterfaces(),handler);
//调用真实对象的方法,完成真实对象的功能
subject.service();
}
}
结果:
before Service
can support a service
after Service
总结:
动态代理类可解决静态代理类中类的集聚膨胀问题,两者区别在于代理对象的定义。动态代理类是在运行过程中生成的,是一个动态类。在静态代理中,代理对象和真实对象共同的接口可以用抽象类或接口的形式来定义,而动态代理中,只能以接口的形式来定义,因为Proxy类中newProxyInstance()的第二个参数是代理类在Subject中定义的所有接口的数组。