java设计模式※结构型※(2)代理模式
代理模式分为静态代理和动态代理
定义:为其他对象提供一种代理以控制对这个对象的访问
一、静态代理
类图如下:
在代理模式中的角色:
● 抽象对象角色:声明了目标对象和代理对象的共同接口,这样一来在任何可以使用目标对象的地方都可以使用代理对象。
● 目标对象角色:定义了代理对象所代表的目标对象。
● 代理对象角色:代理对象内部含有目标对象的引用,从而可以在任何时候操作目标对象;代理对象提供一个与目标对象相同的接口,以便可以在任何时候替代目标对象。代理对象通常在客户端调用传递给目标对象之前或之后,执行某个操作,而不是单纯地将调用传递给目标对象。
抽象对象角色
代码示例:通过代理上网浏览FaceBook
1、创建接口类
1 package design.proxy; 2 public interface IBrowse{ 3 public void browseFaceBook(String serverIp); 4 }
2、创建本地实现类-完成浏览操作
1 package design.proxy; 2 import java.util.Arrays; 3 public class BrowersImpl implements IBrowse { 4 @Override 5 public void browseFaceBook(String serverIp) { 6 if(Arrays.toString(Constant.IPS).contains(serverIp)){ 7 System.out.println("观看faceBook............防火墙拦截..............not found....."); 8 }else{ 9 System.out.println("观看faceBook............通过代理访问..............400.........."); 10 } 11 } 12 13 }
3、通过vpn上网
1 package design.proxy; 2 public class ProxyBrowers implements IBrowse { 3 private IBrowse browse; 4 private String ip; 5 public ProxyBrowers(IBrowse browse){ 6 this.browse = browse; 7 ip = "192.168.2.1"; 8 } 9 public void browseFaceBook(String clientIp) { 10 clientIp = this.ip; 11 browse.browseFaceBook(clientIp); 12 } 13 14 }
4、测试上网是否正常
1 package design.proxy; 2 public class ProxyTest { 3 public static void main(String[] args) { 4 //不架vpn上网 5 IBrowse localBrowse= new BrowersImpl(); 6 localBrowse.browseFaceBook("192.168.1.1"); 7 //使用vpn上网 8 IBrowse browse= new ProxyBrowers(new BrowersImpl()); 9 browse.browseFaceBook("192.168.1.1"); 10 } 11 12 }
5、运行结果
1 观看faceBook............防火墙拦截..............not found..... 2 观看faceBook............通过代理访问..............400..........
可以做到在不修改目标对象的功能前提下,对目标功能扩展。但是因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类,类太多.同时,一旦接口增加方法,目标对象与代理对象都要维护.
二、动态代理
动态代理核心就是将动态代理的代理类使用动态的方式在java运行时来创建。
动态代理需要有一个共同的代理处理类需要实现JDK代理接口InvocationHandler类,实现invoke方法
1、创建接口类
1 package design.dynamicproxy; 2 /** 3 * 被代理的接口 4 */ 5 public interface HelloWorld { 6 void sayHello(String name); 7 }
2、实现类
1 package design.dynamicproxy; 2 3 /*** 4 * 接口的实现类 5 */ 6 public class HelloWorldImpl implements HelloWorld { 7 8 @Override 9 public void sayHello(String name) { 10 System.out.println("Hello " + name); 11 } 12 }
3、针对helloWord接口的代理处理类
可以理解为jdk动态生成代理类$proxy0,执行指定方法后执行的类
1 package design.dynamicproxy; 2 import java.lang.reflect.InvocationHandler; 3 import java.lang.reflect.Method; 4 public class CustomInvocationHandler implements InvocationHandler { 5 private Object target; 6 public CustomInvocationHandler(Object target) { 7 this.target = target; 8 } 9 @Override 10 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 11 /*proxy是具体用jdk生成的代理类 12 *method是要执行的方法 13 *args方法所需要的参数 14 *target表示当前目标对象,jdk在生成代理的时候已经通过反射将目标对象赋值给target 15 *相当于执行: 16 *CustomInvocationHandler cih = new CustomInvocationHandler(new HelloWordImpl()); 17 */ 18 System.out.println("Before invocation"); 19 Object retVal = method.invoke(target, args); 20 System.out.println("After invocation"); 21 return retVal; 22 } 23 }
4、通过main方法实现调用
1 package design.dynamicproxy; 2 import java.lang.reflect.Proxy; 3 public class ProxyTest { 4 public static void main(String[] args) { 5 //是否将jdk动态生成的代理类写入硬盘 6 System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true"); 7 CustomInvocationHandler handler = new CustomInvocationHandler(new HelloWorldImpl()); 8 HelloWorld proxy = (HelloWorld) Proxy.newProxyInstance( 9 ProxyTest.class.getClassLoader(), 10 new Class[]{HelloWorld.class}, 11 handler); 12 proxy.sayHello("Mikan 1"); 13 } 14 15 }
关于:Proxy.newProxyInstance()
该方法需要三个参数,完整的写法:
static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h)
方法是在Proxy类中是静态方法,且接收的三个参数依次为:
ClassLoader loader:指定当前目标对象使用类加载器,获取加载器的方法是固定的Class<?>[] interfaces:目标对象实现的接口的类型,使用泛型方式确认类型InvocationHandler h:事件处理,执行目标对象的方法时,会触发事件处理器的方法,会把当前执行目标对象的方法作为参数传入
参考:
http://www.cnblogs.com/java-my-life/archive/2012/04/23/2466712.html
http://www.cnblogs.com/cenyu/p/6289209.html
http://blog.csdn.net/mhmyqn/article/details/48474815
http://www.iteye.com/topic/683613/

浙公网安备 33010602011771号