代理模式

/ 设计模式

代理模式(Proxy)

为其他对象提供一种代理以控制这个对象的访问

GoF23种设计模式中,属于结构型模式( Structural patterns)

生活中有很多代理,比如说经济人,经销商,房产中间等等。为什么会出现这种职业呢?

明星总不能凡事都亲力亲为,通过经纪人可以减轻自身在商务、关系处理等等方面的事务。

厂家可以通过经销商获取到更广的客源,更容易把自身的产品推销出去。

房产中介作为房东的代理,可以帮房东分担出租、销售上的压力。

代理模式本质与上述情形一样,其实就是作为中间商,为代理对象赋能,增强代理对象能力。同时也会对代理对象进行保护,可以控制代理对象的访问权限。

实例

代理模式总览.png

角色说明

举例

在java代码里,代理通常有静态代理和动态代理两种形式。

静态代理

静态模式举例

角色说明

代码详情

public interface Star {
    void show();
}
public class Ordin implements Star{
    @Override
    public void show() {
        System.out.println("super star ordin's showTime!!! ");
    }
}
public class Agent implements Star{

    private Ordin ordin;

    public Agent(Ordin ordin) {
        this.ordin = ordin;
    }

    @Override
    public void show() {
        beforeShow();
        ordin.show();
        afterShow();
    }

    private void beforeShow(){
        System.out.println("商谈演出计划,粉丝应援...");
    }

    private void afterShow(){
        System.out.println("结账分红...");
    }
}
public class Client {
    public static void main(String[] args) {

        Ordin ordin = new Ordin();

        System.out.println("==不使用经纪人==");
        ordin.show();

        System.out.println("\n==使用经纪人后==");
        Agent agent = new Agent(ordin);
        agent.show();
    }
}
==不使用经纪人==
super star ordin's showTime!!! 

==使用经纪人后==
商谈演出计划,粉丝应援...
super star ordin's showTime!!! 
结账分红...

使用静态代理我们明显可以看到明星的能力得到了增强。但是这样编码对于系统拓展极不灵活,如果经纪人同时作为另一个明星的代理,这边还需要更改原有对象,违反开闭原则。

如果想要动态的更换代理对象,Java中可以使用jdk动态代理Cglib动态代理实现。

jdk动态代理和Cglib动态代理比较

  1. jdk动态代理是实现了被代理对象的接口,Cglib是继承了被代理对象。因此使用Cglib时,需要特别注意final类的代理。
  2. jdk是直接写Class字节码,Cglib使用ASM框架写Class字节码,相比之下jdk生成代理类效率更好一些。
  3. jdk底层是通过反射机制调用代理方法,而Cglib是通过FastClass机制(生成代理和被代理类,通过index直接调用,避免反射调用)调用方法,Cglib执行效率更高。

动态代理

动态模式举例

public interface Star {
    void show();
}
public class Ordin implements Star{
    @Override
    public void show() {
        System.out.println("super star ordin's showTime!!! ");
    }
}
public class OrdinT implements Star {
    @Override
    public void show() {
        System.out.println("super star ordinT's showTime!!! ");
    }
}
public class Agent implements InvocationHandler {

    private Star star;

    public Agent(Star star) {
        this.star = star;
    }

    public Object getProxy() {
        Class cls = star.getClass();
        return Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), this);
    }

    private void beforeShow() {
        System.out.println("商谈演出计划,粉丝应援...");
    }

    private void afterShow() {
        System.out.println("结账分红...");
    }


    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        beforeShow();
        Object object = method.invoke(star, args);
        afterShow();
        return object;
    }
}
public class Client {
    public static void main(String[] args) {

        System.out.println("==代理Ordin==");
        Ordin ordin = new Ordin();
        Star ordinProxy = (Star)new Agent(ordin).getProxy();
        ordinProxy.show();

        System.out.println("\n==动态代理OrdinT==");
        OrdinT ordinT = new OrdinT();
        Star ordinTProxy = (Star)new Agent(ordinT).getProxy();
        ordinTProxy.show();
    }
}
==代理Ordin==
商谈演出计划,粉丝应援...
super star ordin's showTime!!! 
结账分红...

==动态代理OrdinT==
商谈演出计划,粉丝应援...
super star ordinT's showTime!!! 
结账分红...

实例

总结

代理模式可以增强目标对象和保护目标对象。