代理模式
简介
代理模式和生活中的代理是一样的某个对象的方法或属性希望被别人访问,但是又不希望对方直接来访问,可以在中间加个代理,通过代理向对象提供自己的服务。
结构展示
抽象角色:定义代理角色和真实角色的公共对外方法
真实角色:实现抽象角色,实现业务逻辑来共代理角色调用
代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并附加自己的操作,一般将同一的流程控制放在代理角色中
分类
静态代理:由程序员来自己定义代理类
动态代理:由程序动态生成代理类(JDK自带的动态代理、javaassist字节码操作库实现、CGLIB)
静态代理
Star.java是公共接口
package com.dy.xidian; public interface Star { void confer(); void signContract(); void bookTicket(); void sing(); }
RealStar.java 代表明星本人
package com.dy.xidian; public class RealStar implements Star { @Override public void confer() { System.out.println("会面"); } @Override public void signContract() { System.out.println("签协议"); } @Override public void bookTicket() { System.out.println("订票"); } @Override public void sing() { System.out.println("唱歌"); } }
ProxyStar.java表示经纪人
这个经纪人并不一定要全部使用真实角色的功能,比如签协议、订票等,自己就可以直接实现。
package com.dy.xidian; public class ProxyStar implements Star { private Star realStar; public ProxyStar(Star star) { this.realStar = star; } @Override public void confer() { realStar.confer(); } @Override public void signContract() { System.out.println("xxx"); } @Override public void bookTicket() { System.out.println("xxx"); } @Override public void sing() { realStar.sing(); } }
client.java
package com.dy.xidian; public class Client { public static void main(String[] args) { Star star = new ProxyStar(); star.confer(); star.bookTicket(); star.sing(); } }
动态代理
JDK自带实现动态代理
使用方式:
package com.dy.xidian; import java.lang.reflect.Proxy; public class Client { public static void main(String[] args) { Star realStar = new RealStar(); StarHandler handler = new StarHandler(realStar); Star proxy = (Star) Proxy.newProxyInstance( Star.class.getClassLoader(), new Class[]{Star.class}, handler); proxy.bookTicket(); proxy.sing(); } }
在代码中,我们需要一个真实对象,还需要一个控制器对象。控制器的主要作用就是流程控制(比如满足一定条件明星才进行演出之类的)。通过使用JAVA中自带的Proxy类来生成相应的代理对象。Proxy.newProxyInstance()第一个参数需要一个类加载器,通常从已加载对象中获取类加载器,第二个参数是代理需要实现哪些接口,第三个参数就是控制器了。
package com.dy.xidian; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class StarHandler implements InvocationHandler { Star realStar; public StarHandler(Star realStar) { this.realStar = realStar; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { method.invoke(realStar, args); return null; } }
这里使用到了反射机制,当用户每次调用代理的方法的时候,都被重定向到控制器中的invoke方法上。第一个参数是用户使用的是哪个代理(一般情况下代理只有一个,这里不用关心),第二个参数是调用的代理的那个方法(已经被封装成Method对象),第三个参数是调用代理方法时传递的参数。method.invoke(realStar, args)就是告诉真实对象我要调用你那个方法。
应用场景
安全代理:屏蔽对真实对象的直接访问
远程代理:通过代理类来处理远程方法调用
延迟加载:先加载轻量级的代理对象,等真正用时才加载真实对象