代理模式总结

315 阅读4分钟

1 简介

代理模式也被陈各位委托模式,它是结构型设计模式的一种。在现实生活中我们用到类似代理模式的场景有很多,比如代理上网、打官司等。
定义:为其他对象提供一种代理以控制对这个对象的访问。
代理模式的结构如下图所示:

在代理模式中有如下角色:

  • Subject:抽象主题类,声明真实主题与代理的共同接口方法
  • RealSubject:真实主题类,代理类所代表的真实主题。客户端通过代理类间接的调用真实主题类的方法
  • Proxy:代理类,持有对真实主题类的引用,在其所实现的接口方法中调用真实主题类中的相应的接口方法执行
  • Client:客户端类

2 代理模式的简单实现

我要购买哈尔滨红肠,但是不能亲自去,于是就托在哈尔滨的朋友帮我购买。

2.1 抽象主题类

抽象主题类具有真实主题类和代理的共同接口方法,共同的方法就是购买:

public interface IShop{
    void buy();
}

2.2 真实主题类

这个购买者,也就是我,实现了IShop接口提供的buy()方法,如下所示:

public class Person implements IShop{
    @Override
    public void buy(){
        System.out.println("购买");
    }
}

2.3 代理类

我找的代理类同样也要实现IShop接口,并且要持有被代理者,在buy()方法中调用了被代理者的buy()方法:

public class Purchasing implements IShop{
    private IShop mShop;
    public Purchasing(IShop shop){
        mShop = shop;
    }
    
    @Override
    public void buy(){
        mShop.buy();
    }
}

2.4 客户端类

public class Client{
    public static void main(String[] args){
        IShop person = new Person();
        IShop purchasing = new Purchasing(person);
        purchasing.buy();
    }
}

客户端类的代码就是代理类包含了真实主题类(被代理者),最终调用的都是真实主题类(被代理者)实现的方法。在上面的例子中就是Person类的buy方法,所以运行的结果就是“购买”。

3 动态代理的实现

从编码的角度来说,代理模式分为静态代理和动态代理。上面的例子就是静态代理,在代码运行前就已经存在了代理类的class编译文件;而动态代理则是在代码运行时通过反射来动态的生成代理类的对象,并确定到底来代理谁。也就是我们在编码阶段无需知道代理谁,代理谁将会在代码运行时决定。Java提供了动态的代理接口InvocationHandler,实现该接口需要重写invoke()方法。下面我们在上面静态代理的例子上做修改。首先创建动态代理类,代码如下所示:

public void DynammicPurchasing implements InvocationHander{
    private Object obj;
    public DynamicPurchasing(Object obj){
        this.obj = obj;
    }
    
    @Override
    public Object invoke(Object proxy,Method method,Object[] args) throws Throwable{
        Object result = method.invoke(obj,args);
        if(method.getName().equals("buy")){
            System.out.println("买买买");
        }
        return result;
    }
}

在动态代理中我们声明一个Object的引用,该引用指向被代理类,我们调用被代理类的具体方法在invoke方法中执行。接下来我们修改客户端代码:

public class Client{
    public static void main(String[] args){
        //创建Person
        IShop person = new Person();
        //创建动态代理
        DynamicPurchasing mDynamicPurchasing = new DynamicPurchasing(person);
        //创建person的ClassLoader
        ClassLoader loader = person.getClass().getClassLoader();
        //动态创建代理
        IShop purchasing = (IShop)Proxy.newProxyIntance(loader,new Class[]{IShop.class},mDynamicPurchasing);
        purchasing.buy();
    }
}

4代理模式的类型和优点

4.1 编码分类

  • 静态代理:在代码运行前就已经存在了代理类的class编译文件
  • 动态代理:在代码运行时通过反射来动态的生成代理类的对象,并确定到底来代理谁

4.2 适用范围分类

  • 远程代理:为一个对象在不同的地址空间提供局部代表,这样系统就可以将Server部分的实现隐藏
  • 虚拟代理:使用一个代理对象表示一个十分耗费资源的对象并在真正需要时才创建
  • 安全代理:用来控制真实对象访问时的权限。一般用于真实对象有不同的访问权限时
  • 智能指引:当调用真实的对象时,代理处理另外一些事,比如计算真实对象的引用计数,当该对象没有引用时,可以自动释放它;或者访问一个十几对象时检查是否已经能够锁定他,确保其不能改变他

4.3 优点

  • 真实主题类就是实现实际的业务逻辑,不用关系你其他非本职的工作
  • 真实主题类随时都会发生变化;但是因为他实现了公共的接口,所以代理类可以不做任何修改就能够使用

参考《Android进阶之光》 作者:刘望舒