设计模式之代理模式

简介

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

W3sDesign_Proxy_Design_Pattern_UML

组成

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

优点

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

代理模式

静态代理

interface ISinger{
    void sing();
}

class Singer implements ISinger{
    @Override
    public void sing() {
        System.out.println("唱歌");
    }
}

class ProxySinger implements ISinger {
    private ISinger target;

    public ProxySinger(ISinger target) {
        this.target = target;
    }

    @Override
    public void sing() {
        System.out.println("唱歌前");
        target.sing();
        System.out.println("唱歌后");
    }
}

class Client {
    public static void main(String[] args) {
        ProxySinger proxySinger = new ProxySinger(new Singer());
        proxySinger.sing();
    }
}

动态代理

JDK代理

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

interface ISinger {
    void sing();
}

class Singer implements ISinger {
    @Override
    public void sing() {
        System.out.println("唱歌");
    }
}


public class Client {
    public static void main(String[] args) {
        Singer target = new Singer();
        //获取代理类
        ISinger proxyInstance = (ISinger) Proxy.newProxyInstance(
                //类加载器
                target.getClass().getClassLoader(),
                //接口列表
                target.getClass().getInterfaces(), new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("唱歌前");
                        Object returnValue = method.invoke(target, args);
                        System.out.println("唱歌后");
                        return returnValue;
                    }
                });
        proxyInstance.sing();
    }
}

缺点:需要实现接口,如果没有接口,需要使用CGLib代理

CGLib代理

需要CGlib包,并且类是可继承的(非final修饰),对象方法不能是(final或者static),否则会被忽略。

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;


class Singer {
    public void sing() {
        System.out.println("唱歌");
    }
}

class ProxyFactory implements MethodInterceptor {
    private Object target;

    public Object getInstance(Object target) {

        this.target = target;
        //用于创建代理类
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(target.getClass());
        enhancer.setCallback(this);
        return enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("唱歌前");
        //调用父类方法
        Object returnValue = methodProxy.invokeSuper(o, objects);
        System.out.println("唱歌后");
        return returnValue;
    }
}

public class Client {
    public static void main(String[] args) {
        Singer target = new Singer();
        ProxyFactory proxyFactory = new ProxyFactory();
        Singer instance = (Singer) proxyFactory.getInstance(target);
        instance.sing();
    }
}

CGlib基于继承

Q.E.D.

知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议

人生中没有四季 唯有那寒冬的荒野