结构型设计模式 — 代理模式

把时间用在思考上是最能节省时间的事情。 — 卡曾斯

写在前面

本篇讲解代理模式,分静态代理动态代理两部分,由浅入深更好的理解代理模式。

代理模式又被称为委托模式,在现实生活中类似代理模式这种场景有很多,比如请律师打官司,代购,代理上网等。

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

代理模式.jpg

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

静态代理

通过一个例子来认识代理模式,我看好了一双球鞋,想托代购小芳帮我买,而我只需要给她钱就好,至于她怎么买去哪买我并不关心,最终能把鞋子送到我手里就好了。

我和代购小芳都具有"买"的行为,而代购小芳代替我去买,所以我和代购小芳不同的是代购小芳有买的过程,我却没有。

1.抽象主题类

我和代购小芳都具有“买”的行为,我是真实主题类,代购小芳是代理类,所以要声明真实主题与代理类的公共接口方法。

/**
 * 抽象主题类
 */
public interface Subject {
    
    void buy(String goods);
}
2.真实主题类

我才是真正要买这双鞋子的人,然而我也具有“买”的行为,所以我要实现抽象主题类,实现buy()方法。

/**
 * 真实主题类
 */
public class RealSubject implements Subject {
    @Override
    public void buy(String goods) {
        Log.d("RealSubject", "哈哈哈哈,好开心,我买到了喜欢的" + goods);
    }
}
3.代理类

代购小芳是帮我买,也具有“买”的行为,而且还要将买到的鞋子给我,所以代购小芳也要实现抽象主题类,实现buy()方法。

/**
 * 代理类
 */
public class Proxy implements Subject{

    private Subject mSubject;

    public Proxy(Subject subject) {
        mSubject = subject;
    }

    @Override
    public void buy(String goods) {
        // 代购小芳代替我买,买到后把鞋子给我
        mSubject.buy(goods);
    }
}
4.代购

现在就让代购小芳正式的帮我买鞋子了。

/**
 * 客户端
 */
public class Client {

    public Client() {
        // 这是我
        Subject realSubject = new RealSubject();
        // 将我作为参数实例化代购小芳
        Subject proxy = new Proxy(realSubject);
        // 代购小芳替我买球鞋了
        proxy.buy("好看的球鞋");
    }
}

动态代理

从上面静态代理的例子中可以看出,代购小芳只为我一个人买东西,这一趟代购不赔钱就谢天谢地了,代购小芳作为一名职业代购不可能只给我一个人买东西, 她还会帮许多人购买商品赚取利润。那么如何解决这个问题呢,动态代理横空出世了。

静态代理在编译期间就已经决定了代理谁,动态代理在编译期间不会决定代理谁,而是在代码运行时通过反射动态的生成代理类的对象,Java提供了动态代理的接口InvocationHandler,实现这个接口需要重写invoke()方法。

1.代理类

现在让我们来修改代理类,让代购小芳不只再为我自己买东西。

/**
 * 动态代理类
 */
public class InvocationProxy implements InvocationHandler {

    private Subject mSubject;

    public InvocationProxy(Subject subject) {
        mSubject = subject;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Log.d("invoke", "成功购买到所需商品 = " + args[0]);
        return method.invoke(mSubject, args);
    }
}
2.代购

代购小芳现在不可以为我代购,还能为别人代购,那么先以为我代购为例,为其他人代购的实现方式也一样。

/**
 * 客户端
 */
public class InvocationClient {

    public InvocationClient() {
        // 这是我
        Subject realSubject = new RealSubject();
        // 创建动态代理类
        InvocationHandler proxy = new InvocationProxy(realSubject);
        // 调用Proxy.newProxyInstance()生成动态代理类
        Subject subject = (Subject) Proxy.newProxyInstance(realSubject.getClass().getClassLoader(), new Class[]{Subject.class}, proxy);
        subject.buy("好看的球鞋");
    }
}

总结

代理模式从编码角度来说分为静态代理和动态代理,从适用范围来说分为远程代理,虚拟代理,安全代理和智能指引四种类型,分别如下:

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

代理模式的优点:

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

你可能感兴趣的:(结构型设计模式 — 代理模式)