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/

posted @ 2017-05-22 22:14  jeasy  阅读(70)  评论(0)    收藏  举报