后端

代理模式

2022-07-29  本文已影响0人  字字经心

代理模式

代理模式定义,为另外一个对象提供一个替身以控制对这个对象的访问,是一个控制对象访问的模式。常用的几种控制访问方式有

假设现在有一个远程的饮料贩卖机器,想在本地监控贩卖情况,就可以在本地产生一个远程的代理对象,本地程序通过本地远程代理来和远程真实对象进行通信。这样客户所做的就像在做远程调用,但是其实只是调用本地代理对象上的方法。再由代理处理所有网络通信的底层细节。

proxy1.png

保护代理,如果一个对象里面的方法不是对每一个对象都是公开的,就可以为对象创建保护代理,每次调用对象方法时触发保护。

假设有一个帮忙实现约会的服务系统,这套系统能鼓励顾客找到可能的配对对象。系统有一个Person bean 对象,允许设置或取得一个人的信息。

public interface PersonBean{
    String getName();
    String getGender();
    // 取得兴趣爱好
    String getInterests();
    // 取得评分1~10
    int getHotOrNotRating();
    
    void setName(String name);
    void setGender(String gender);
    // 设置兴趣爱好
    void setInterests(String interests);
    // 每一次评分都会,再计算平均评分
    void setHotOrNotRating(int rating);
}

// PersonBean 实现
public class PersonBeanImpl implements PersonBean{
    String name;
    String gender;
    String interests;
    int rating;
    int ratingCount = 0;
    
    public String getName(){
        return name;
    }
    
    public int getHotOrNotRating(){
        if(ratingCunt == 0) return 0;
        return (rating/ratingCount);
    } 
    // 其他方法 .....
    
    public void setInterests(String interests){
        this.interests = interests;
    }
    
    public void setHotOrNotRating(int rating){
        this.rating += rating;
        ratingCount++;
    }
}

但是不久就会有人抱怨有人居然篡改了我的兴趣,还有有人居然给自己评高分,以拉高自己的HotOrNotRating 值。所以顾客不可以给自己评分,也不可以修改别人的信息。我们可以为PersonBean 创建保护代理,先看看类图

proxy2.png

在这里PersonBean 就是RealSubject,

接下来看看具体的代码实现,创建控制自己对主题访问的对象OwnerInvocationHandler,控制别人对主题访问的NonOwnerInvocationHandler 代码类似

import java.lang.reflect.*;

// InvocationHandler 是reflect 里面的接口,实现其中的invoke 方法
public class OwnerInvocationHandler implements InvocationHandler{
    PersonBean Person;
    public OwnerInvocationHandler(PersonBean person){
        this.person = person;
    }
    
    public Object invoke(Object proxy, Method method, object[] args) throws IllegallAccessException{
        try{
            if(method.getName().startsWith("get")){
                return method.invoke(perosn, agrs);
            }else if(method.getName().equals("setHotOrNotRating")){
                // 自己不能给自己评分,调用此方法时抛异常
                throw new IllegalAccessException();
            }else if(method.getName().startWith("set")){
                return method.invoke(perosn, agrs);
            }
        }catch(InvocationTargetException e){
            e.printStackTrace();
        }
        return null;
    }
}

创建getOwnerProxy 代理的方法返回personBean 对象,该代理用于保护自己对personBean 的访问。

// 创建getOwnerProxy 代理
PersonBean getOwnerProxy(PersonBean person){
    // Proxy 是java reflect 包里面的类
    return (PersonBean)Proxy.newProxyInstance(
        person.getClass().getClassLoader(),
        person.getClass().getInterfaces(),
        new OwnerInvocationHandler(person)
        );
}

// 类似的getNonOwnerProxy(),返回NonOwnerInvocationHandler 的代理

// 测试一下,
PersonBean personA = new PersonBean();
personBean ownerProxy = getOwnerProxy(personA);
try{
    // 代理会触发 OwnerInvocationHandler invoke() 
    ownerProxy.setHotOrNotRating(10);
}catch (Exception e){
    System.out.println('Canot set rating from owner proxy);
}

Java 在java.lang.reflect 包中有自己的代理支持,利用这个包可以再运行时动态创建一个代理类,实现一个或多个接口,并将方法的调用转发到你所指定的类。因为实际的代理类是来运行时创建的,所以称这个Java 技术为:动态代理

复合模式

复合模式:结合两个或两个以上的模式,组成一个解决方案,解决一再发生的一般性问题。我们看看 mvc 模式在web 中的应用,里面也用了好几种设计模式

proxy3.png

欢迎大家给我留言,提建议,指出错误,一起讨论学习技术的感受!

上一篇 下一篇

猜你喜欢

热点阅读