Java动态代理模式 -- 保护代理

意义

将接口的调用统一到一个函数里处理,然后再去具体实例调用相应的方法,充当一个分发器的作用

user -> handler -> method

字典

动态:指的是在程序运行时才创建代理类

代理:与被代理类具有相同的属性,也就是被代理类有run方法,它也有run方法

保护代理:限制接口类的某些方法给特定的对象使用

Proxy类:Java反射包自带,其中newProxyInstance可以返回接口实现类的实例

组成

1.接口

Person类:其中有name与score相关的方法

自己本人可以修改名字但不能修改分数

别人可以修改分数不能修改名字

public interface PersonBean {
    String getName();
    void setName(String name);

    int getScore();
    void setScore(int score);
}

 

2.实现接口的类

public class PersonBeanImpl implements PersonBean {
    private String name;
    private int score;

    public PersonBeanImpl (){
    }

    public PersonBeanImpl (String name,int score){
        this.name = name;
        this.score = score;
    }

    public String getName (){
        return name;
    }

    public void setName (String name){
        this.name = name;
    }

    public int getScore (){
        return score;
    }

    public void setScore (int score){
        this.score = score;
    }
}

 

3.实现InvocationHandler的handler类

  它的invoke方法利用反射,PersonBean的方法调用时会来调用invoke,因此可以在invoke方法体实现相应逻辑,

  实例中就是限定某些方法允许调用,某些方法会抛出异常

  3.1 自身handler:当创建这个handler实例时,就说明只能修改name不能修改score

public class OwnInvocationHandler implements InvocationHandler {
    // 需要代理的对象
    private PersonBean personBean;

    OwnInvocationHandler (PersonBean personBean){
        this.personBean = personBean;
    }

    // 代理设置规则
    public Object invoke (Object proxy ,Method method, Object[] args) throws Throwable{
        String methodName = method.getName();
        // 自己不能设置自己的分数
        if ("setScore".equals(methodName)) {
            throw new IllegalAccessException("自己不能给自己打分");
        } else {
            return method.invoke(personBean, args);
        }
    }
}

  3.2 他人handler:当创建这个handler实例时,就说明只能修改score不能修改name

public class OtherInvocationHandler implements InvocationHandler {
    // 需要代理的对象
    private PersonBean personBean;

    OtherInvocationHandler (PersonBean personBean){
        this.personBean = personBean;
    }

    // 代理设置规则
    public Object invoke (Object proxy ,Method method, Object[] args) throws Throwable{
        String methodName = method.getName();
        // 不能修改别人的名字
        if ("setName".equals(methodName)) {
            throw new IllegalAccessException("不能修改别人的名字");
        } else {
            return method.invoke(personBean, args);
        }
    }
}

 

4.生产handler类的工厂

通过Proxy的newProxyInstance获取PersonBean对象

它的主要作用:将传入的personBean与指定的InvocationHandler绑定,当PersonBean调用方法时,会去InvocationHandler调用invoke方法

public class ProxyFactory {
    /**
     * 获得 个人 代理
     * @param personBean
     * @return
     */
    public PersonBean getOwnerProxy(PersonBean personBean) {
        return (PersonBean)Proxy.newProxyInstance(personBean.getClass().getClassLoader(),
                personBean.getClass().getInterfaces(),
                new OwnInvocationHandler(personBean));
    }

    /**
     * 获得 其他人 代理
     * @param personBean
     * @return
     */
    public PersonBean getOtherProxy(PersonBean personBean) {
        return (PersonBean)Proxy.newProxyInstance(personBean.getClass().getClassLoader(),
                personBean.getClass().getInterfaces(),
                new OtherInvocationHandler(personBean));
    }
}

 

参考《Head First 设计模式》 -- P474

posted @ 2018-08-18 19:50  逃跑旅馆  阅读(201)  评论(0编辑  收藏  举报