代理模式(Proxy)

定义

  为其他对象提供一种代理以控制对这个对象的访问。

UML结构图

  

例子

  一个人希望去追求一个女生,但是不好意思直接送礼物给女生,所以就只有找一个女生的朋友,代表他去送礼物,和女生直接接触的并不是该追求者,而是中间的代理对象。

package com.csdhsm.designpattem.proxy;

/**  
 * @Title:  GivenGift.java   
 * @Description: 定义一个公用的接口,也就是类图中的Subject
 * @author: Han   
 * @date:   2016年6月20日 下午3:43:42   
 */  
public interface GivenGift {
    
    //送花
    public void giveFlower();
    
    //送书
    public void giveBook();
    
    //送钱
    public void giveMoney();
}

  女生

package com.csdhsm.designpattem.proxy;

/**  
 * @Title:  SchoolGirl.java   
 * @Description: 女生类
 * @author: Han   
 * @date:   2016年6月20日 下午3:46:45   
 */  
public class SchoolGirl {
    
    private String name;
    
    public SchoolGirl(String name) {
        this.name = name;
    }
    
    public String getName() {
        return name;
    }
}

  追求者

package com.csdhsm.designpattem.proxy;

/**  
 * @Title:  Pursuit.java   
 * @Description: 追求者,但是不好意思直接给MM送礼物
 * @author: Han   
 * @date:   2016年6月20日 下午3:43:14   
 */  
public class Pursuit implements GivenGift {

    private SchoolGirl mm;
    
    public Pursuit(SchoolGirl mm) {
        this.mm = mm;
    }
    
    @Override
    public void giveFlower() {
        System.out.println("给" + mm.getName() + "送花!");
    }

    @Override
    public void giveBook() {
        System.out.println("给" + mm.getName() + "送书!");
    }

    @Override
    public void giveMoney() {
        System.out.println("给" + mm.getName() + "送钱!");
    }
}

  代替送礼物的人

package com.csdhsm.designpattem.proxy;

/**  
 * @Title:  Proxy.java   
 * @Description: 代理类,代替Pursuit去送东西
 * @author: Han   
 * @date:   2016年6月20日 下午3:42:51   
 */  
public class Proxy implements GivenGift {

    private Pursuit pursuit;
    
    public Proxy(SchoolGirl mm) {
        if(pursuit == null) {
            pursuit = new Pursuit(mm);
        } 
    }
    
    @Override
    public void giveFlower() {
        pursuit.giveFlower();
    }

    @Override
    public void giveBook() {
        pursuit.giveBook();
    }

    @Override
    public void giveMoney() {
        pursuit.giveMoney();
    }
}

  客户端

package com.csdhsm.designpattem.proxy;

public class Solution {
    
    public static void main(String[] args) {
        SchoolGirl mm = new SchoolGirl("小美");
        Proxy proxy = new Proxy(mm);
        
        proxy.giveBook();
        proxy.giveFlower();
        proxy.giveMoney();
    }
}

  OK,代理模式成功。

动态代理

  上面的代理属于静态代理,前段时间再看AOP,研究了下动态代理,记录下来,方便以后回忆。

  动态代理:在程序运行时,运用反射机制动态创建而成。

动态代理例子

package com.csdhsm.dynamicproxy;

/**  
 * @Title:  Subject.java   
 * @Description: 一个会跑,会打招呼的接口
 * @author: Han   
 * @date:   2016年6月20日 下午4:08:11   
 */  
public interface Subject {
    
    public void run();
    
    public void hello(String str);
}
package com.csdhsm.dynamicproxy;

/**  
 * @Title:  RealSubject.java   
 * @Description: 真实的对象类
 * @author: Han   
 * @date:   2016年6月20日 下午4:10:04   
 */  
public class RealSubject implements Subject {

    @Override
    public void run() {
        System.out.println("I`m running");
    }

    @Override
    public void hello(String str) {
        System.out.println("say hello to " + str);
    }
}

  上面的两个对象一个是Subject接口,一个是RealSubject,接下来是代理对象。

package com.csdhsm.dynamicproxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**  
 * @Title:  DynamicProxy.java   
 * @Description: 动态代理类
 * @author: Han   
 * @date:   2016年6月20日 下午4:10:35   
 */  
public class DynamicProxy implements InvocationHandler {

    private Object subject;
    
    public DynamicProxy(Object subject) {
        this.subject = subject;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        System.out.println("before-----------------");
        method.invoke(subject, args);
        System.out.println("after------------------");
        return null;
    }
}

  想要成为动态代理类,就需要实现InvocationHandler接口,该接口只有一个方法,就是invoke方法,打开API文档。

  该方法是在代理实例上处理相关联的方法的时候调用该方法,我的理解是,在调用关联方法时,用该方法代替,也就是这个方法代理了原方法。

  proxy参数,表示实现方法的代理实例。

  method代理方法,用反射实现该方法。

  args该方法的参数。

  说明:很多同学会有疑问 method.invoke(subject, args); 这句是否可以写成 method.invoke(proxy, args); ,很明显是不可以的,因为proxy是代理对象实例,这样的结果会是

  很明显就是一直在调用相同的方法,陷入死循环中。

  

  客户端

package com.csdhsm.dynamicproxy;

import java.lang.reflect.Proxy;

public class Solution {
    
    public static void main(String[] args) {
        
        Subject subject = new RealSubject();
        DynamicProxy proxy = new DynamicProxy(subject);
        //获取该代理对象
        Subject realSubject = (Subject)Proxy.newProxyInstance(proxy.getClass().getClassLoader(),
                subject.getClass().getInterfaces(), proxy);
        
        realSubject.run();
        realSubject.hello("Jack");
    }
}

  重点在与这个方法Proxy.newProxyInstance(),贴出API

  这个方法返回一个代理实例,其中:

  loader代理对象类加载器

  interfaces接口列表,其中就是关联的方法

  h代理对象

结果

  OK,成功!

 posted on 2016-06-20 16:59  韩思明  阅读(214)  评论(0编辑  收藏  举报