代理模式概述
为什么要有“代理”?
生活中就有很多代理的例子,例如,我现在需要出国,但是我不愿意自己去办签证、预定机票和酒店(觉得麻烦 ,那么就可以找旅行社去帮我办,这时候旅行社就是代理,而我自己就是被代理了。
代理模式的定义:
被代理者没有能力或者不愿意去完成某件事情,那么就需要找个人代替自己去完成这件事,这个人就是代理者, 所以代理模式包含了3个角色: 被代理角色 代理角色 抽象角色(协议)
代理模式UML类图
1、静态代理
这种代理方式需要代理对象和目标对象实现一样的接口。
优点:可以在不修改目标对象的前提下扩展目标对象的功能。
缺点:
- 冗余。由于代理对象要实现与目标对象一致的接口,会产生过多的代理类。
- 不易维护。一旦接口增加方法,目标对象与代理对象都要进行修改。
接口:
public interface Movie {
void play();
}
被代理对象:
public class RealMovie implements Movie{
@Override
public void play() {
System.out.println("正在播放《变形金刚5》");
}
}
代理对象:
public class Cinema implements Movie{
RealMovie realMovie;
public Cinema(RealMovie realMovie) {
this.realMovie = realMovie;
}
@Override
public void play() {
System.out.println("5月1日上新,超值");
realMovie.play();
System.out.println("电影结束!!!");
}
}
测试:
public class Test {
public static void main(String[] args) {
//静态代理
RealMovie realMovie = new RealMovie();
Cinema cinema = new Cinema(realMovie);
cinema.play();
/*
5月1日上新,超值
正在播放《变形金刚5》
电影结束!!!
*/
}
}
2、动态代理
-
概述 : 动态代理就是直接通过反射生成一个代理对象,代理对象所属的类是不需要存在的
-
动态代理的获取:
jdk提供一个Proxy类可以直接给实现接口类的对象直接生成代理对象
动态代理相关api介绍
Java.lang.reflect.Proxy类可以直接生成一个代理对象
- Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)生成一个代理对象
- 参数1:ClassLoader loader 被代理对象的类加载器
- 参数2:Class<?>[] interfaces 被代理对象的要实现的接口
- 参数3:InvocationHandler h (接口)执行处理接口
- 返回值: 代理对象
- 前2个参数是为了帮助在jvm内部生成被代理对象的代理对象,第3个参数,用来监听代理对象调用方法,帮助我们调用方法
- InvocationHandler中的Object invoke(Object proxy, Method method, Object[] args)方法:调用代理类的任何方法,此方法都会执行
- 参数1:代理对象(慎用)
- 参数2:当前执行的方法
- 参数3:当前执行的方法运行时传递过来的参数
- 返回值:当前方法执行的返回值
上面的代码用动态代码实现:
public class Test {
public static void main(String[] args) {
//静态代理
// RealMovie realMovie = new RealMovie();
// Cinema cinema = new Cinema(realMovie);
// cinema.play();
//动态代理
RealMovie realMovie = new RealMovie();
Movie movie = (Movie) Proxy.newProxyInstance(realMovie.getClass().getClassLoader(), realMovie.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("5月1日上新,超值");
method.invoke(realMovie);
System.out.println("电影结束!!!");
return null;
}
});
movie.play();
}
}
案例:对Collection接口进行代理,以前的remove(Object obj)方法是删除集合中第一次出现的元素(比如集合中有多个“abc”,调用remove(“abc”)后只会删除一个元素)。代理后,要求在调用remove(Object obj)方法后,能够删除集合中所有匹配的元素。【动态代理】
public class H41 {
public static void main(String[] args) {
//集合
Collection<String> list = new ArrayList<String>();
Collections.addAll(list,"abc","auc","ahc","abc","abc","abc","akc","abc","abc")
//动态代理
Collection<String> collection = (Collection<String>)Proxy.newProxyInstance(list.getClass().getClassLoader(), list.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object res = method.invoke(list, args);
if(method.getName().equals("remove")){
Iterator<String> it = list.iterator();
while (it.hasNext()){
String next = it.next();
if(next.equals(args[0])){
it.remove();
}
}
}
return res;
}
});
collection.remove("abc");
System.out.println(list);
}
}