代理模式(静态代理、jdk动态代理)

来源:互联网 发布:vscode 远程编辑 编辑:程序博客网 时间:2024/05/17 07:40

1.代理模式的定义:

为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。


2.组成的角色:
抽象角色:通过接口或抽象类声明真实角色实现的业务方法。
代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。
真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。


3.代理模式的好处:

(1).职责清晰
真实的角色就是实现实际的业务逻辑,不用关心其他非本职责的事务,通过后期的代理完成一件完成事务,附带的结果就是编程简洁清晰。
(2).代理对象可以在客户端和目标对象之间起到中介的作用,这样起到了中介解耦的作用和保护了目标对象的作用,并可以附加自己的操作。
(3).高扩展性


4.通过小例子理解代理模式:

public abstract class AbstractTarget {    public abstract void dosomething();}
public class ConcreteTarget extends AbstractTarget {    @Override    public void dosomething() {        System.out.println("go home");    }}
public class MyProxy extends AbstractTarget {    //静态代理    //编译期就已经明确指定了真实需要代理的类就是ConcreteTarget    private AbstractTarget target = new ConcreteTarget();    @Override    public void dosomething() {        target.dosomething();    }}
public static void main(String[] args) {    AbstractTarget target = new MyProxy();    target.dosomething();}
执行结果:

go home


这是一个最简单到代理模式的例子,客户端使用代理的dosomething()方法时,代理类委托给了真实角色ConcreteTarget执行,这就是代理模式。代理类成为客户端与真实角色直接的桥梁,在不同的场景下,这个桥梁可以起到很大的现实作用,这个在本文后面再讲述。

可以看到,该例中由于编译期已经知道代理的真实角色是谁了,所以这种代理模式又叫做静态代理

//静态代理//编译期就已经明确指定了真实需要代理的类就是ConcreteTargetprivate AbstractTarget target = new ConcreteTarget();

5.jdk动态代理

相对静态代理而言,动态代理是值编译器不知道代理的真实角色是谁,需要在运行期才能确定。


我们有一个超级明星的接口。

public interface SuperStar {    void call();    void sing();    void dance();}

有一个歌手实现了超级明星的接口。

public class Singer implements SuperStar {    @Override    public void call() {        System.out.println("我正在休息,不要打扰我");    }    @Override    public void sing() {        System.out.println("唱歌我在行,让我来");    }    @Override    public void dance() {        System.out.println("跳舞找dancer");    }}
但是明星都很忙的,还要耍耍大牌,所以需要一个经纪人作为他的代理人,处理对外事宜。可是现在是用的jdk动态代理了,与先前的例子写法完全不一样了。jdk API中有个InvocationHandler调用处理器的接口。我们需要先定义一个自己的调用处理器。

public class BrokerInvocationHandler implements InvocationHandler {    private SuperStar superStar;    public BrokerInvocationHandler(SuperStar superStar){        this.superStar = superStar;    }    @Override    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {        if (method.getName().equals("sing")){            method.invoke(superStar,args);            System.out.println("歌手同意了,我们准备准备就来");            return null;        }else if (method.getName().equals("dance")){            System.out.println("跳舞别来找我们");            return null;        }else if (method.getName().equals("call")){            System.out.println("人不在,有什么事找我好了");            return null;        }else {            return null;        }    }}
public class BrokerProxy {    public static SuperStar newProxyInstance(SuperStar superStar){        return (SuperStar) Proxy.newProxyInstance(superStar.getClass().getClassLoader(),                superStar.getClass().getInterfaces(),new BrokerInvocationHandler(superStar) );    }}
有了这2个类,代理就算完成了。

public class Test {    public static void main(String[] args) {        SuperStar singer = BrokerProxy.newProxyInstance(new Singer());        singer.sing();        singer.call();        singer.dance();
//true:说明singer的父类就是Proxy
System.out.println(singer.getClass().getSuperclass() == Proxy.class); }}

运行结果:

唱歌我在行,让我来
歌手同意了,我们准备准备就来
人不在,有什么事找我好了
跳舞别来找我们
true


jdk动态代理总结:
     
      1.定义自己的InvocationHandler实现类BrokerInvocationHandler
     
      2.通过Proxy类的newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)方法创建动态代理类
     
      3.通过反射获取动态代理类的构造函数,并通过该构造函数创建代理类实例singer
     
      4.被创建出来的实例singer继承了Proxy类(因此java动态代理只能代理接口,这是由java不支持多继承的设计决定的),实现了目标接口SuperStar
     
      5.调用singer的任意方法,实际上都会先调用到BrokerInvocationHandler中的invoke方法,然后通过反射调用Method的invode方法调用实际被代理的方法
     
      6.调用到BrokerInvocationHandler中的invoke方法时,可以获得被代理方法的信息,因此可以在真正调用invoke方法前、后写上自己的业务逻辑


5.代理模式的变形

在需要用比较通用和复杂的对象指针代替简单的指针的时候,使用 Proxy模式。下面是一些可以使用Proxy模式常见情况:
1) 远程代理(Remote  Proxy)为一个位于不同的地址空间的对象提供一个本地的代理对象。这个不同的地址空间可以是在同一台主机中,也可是在另一台主机中,远程代理又叫做大使(Ambassador)


2) 虚拟代理(Virtual Proxy)根据需要创建开销很大的对象。如果需要创建一个资源消耗较大的对象,先创建一个消耗相对较小的对象来表示,真实对象只在需要时才会被真正创建。 


3) 保护代理(Protection Proxy)控制对原始对象的访问。保护代理用于对象应该有不同的访问权限的时候。


4) 智能指引(Smart Reference)取代了简单的指针,它在访问对象时执行一些附加操作。


5) Copy-on-Write代理:它是虚拟代理的一种,把复制(克隆)操作延迟到只有在客户端真正需要时才执行。一般来说,对象的深克隆是一个开销较大的操作,Copy-on-Write代理可以让这个操作延迟,只有对象被用到的时候才被克隆。

6)缓存代理(Cache Proxy)


7)防火墙代理(Application Gateway


8)同步代理

等等。











1 0
原创粉丝点击