代理模式

1、简介

1.1 代理是一个中间者的角色
它屏蔽了访问方和委托方之间的直接接触。也就是说访问方不能直接调用委托方的这个对象,而是必须实例化一个跟委托方有同样接口的代理方,通过这个代理方来完成对委托方的调用。访问方只和代理方打交道,这个代理方有点像掮客的角色,现实生活中的代理类似于中介机构。

1.2 什么时候需要用到代理模式呢?

  • 访问方不想和委托方有直接接触,或者直接接触有困难。
  • 访问方对委托方的访问需要增加额外的处理,例如访问前和访问后都做一些处理。这种情况下我们不能直接对委托方的方法进行修改,因为这样会违反“开闭原则”。

1.3 代理模式有两类:静态代理和动态代理,下面我们通过代码分别详细说明。

2、静态代理

静态代理的代理类每次都需要手动创建。

public interface Icar {
    void move();
}
public class Benz implements Icar{
    @Override
    public void move() {
        System.out.println("Benz move ...");
    }
}
/**
 * 静态代理
 */
public class BenzProxy implements Icar{
    private Benz benz;

    public BenzProxy() {
        benz = new Benz();
    }

    @Override
    public void move() {
        //做一些前置工作 例如:检查车子的状况
        System.out.println("检查车子的状况。。。");
        benz.move();
        //做一些后置工作 例如检查结果
        System.out.println("车子2020-10-21号出厂,空调坏了。");

    }
}

最后调用

public class ProxyMain {
    public static void main(String[] args) {
        BenzProxy benzProxy = new BenzProxy();
        benzProxy.move();
    }
}
3、 动态代理

动态代理的代理类可以根据委托类自动生成,而不需要像静态代理那样通过手动创建。动态代理类的代码不是在Java代码中定义的,而是在运行的时候动态生成的。这里主要用到InvocationHandler接口。

//动态代理类
public class CarHandler implements InvocationHandler {
    //目标类的引用
    private Object target;

    public CarHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object object, Method method, Object[] args) throws Throwable {
        //做一些前置工作 例如:检查车子的状况
        before();
        Object result = method.invoke(target, args);
        //做一些后置工作 例如检查结果
        after();
        return result;
    }
    private void before() {
        System.out.println("检查车子的状况。。。");
    }
    private void after() {
        System.out.println("车子2019-10-1号出厂,空调坏了。");
    }
}

调用动态代理:

public static void main(String[] args) {
    ICar iCar = new Benz();
    InvocationHandler handler = new CarHandler(iCar);
    ICar proxy = (ICar) Proxy.newProxyInstance(ICar.class.getClassLoader(), new Class[]{ICar.class}, handler);
    proxy.move();
}
4、 动态代理应用:简单工厂

接着上面动态代理调用方的使用方式,通过工厂模式加上泛型的方式,优化一下动态代理的生成和调用。

public class ProxyFactory {
    private T client;//目标对象
    private IBefore before;
    private IAfter after;

    public  T createProxy(){
        ClassLoader loader = client.getClass().getClassLoader();
        Class[] interfaces = client.getClass().getInterfaces();
        InvocationHandler handler = new InvocationHandler() {
            @Override
            public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
                if ("getName".equals(method.getName())){
                    //可根据name值过滤方法
                }
                //前置
                if (before != null){
                    before.doBefore();
                }
                //执行目标对象的方法
                Object result = method.invoke(client, objects);
                //后置
                if (after != null){
                    after.doAfter();
                }
                return result;
            }
        };
        return (T) Proxy.newProxyInstance(loader,interfaces,handler);
    }

    public void setClient(T client) {
        this.client = client;
    }

    public void setBefore(IBefore before) {
        this.before = before;
    }

    public void setAfter(IAfter after) {
        this.after = after;
    }
}

创建前后置接口

public interface IAfter {
    void doAfter();
}
public interface IBefore {
    void doBefore();
}

使用和具体的产品业务分离出来了,方便维护和拓展:

public static void main(String[] args) {
    //创建工厂
    ProxyFactory factory = new ProxyFactory();

    factory.setBefore(new IBefore() {
        @Override
        public void doBefore() {
            System.out.println(" doBefore...");
        }
    });
    factory.setClient(new Benz());

    factory.setAfter(new IAfter() {
        @Override
        public void doAfter() {
            System.out.println(" doAfter...");
        }
    });
    //创建代理
    ICar iCar = (ICar) factory.createProxy();
    iCar.move();
}
5、 动态代理应用:AOP

AOP的英文全称是Aspect-Oriented Programming,即面向切面编程。AOP的实现方式之一是动态代理。
简单来说,AOP能够动态地将代码切入指定的位置,在指定位置上实现编程,从而达到动态改变原有代码的目的。
上面的IBefore和IAfter接口实际上就是简单地实现了AOP,例如在invoke具体方法之前和之后插入一些操作。
另外Proxy.newProxyInstance这个方法:

  public static Object newProxyInstance(ClassLoader 
    loader,Class[] interfaces,InvocationHandler h)
  • loader:委托类的classLoader。
  • interfaces:代理类需要实现的接口,这个接口同委托类的接口。
  • h:调用处理器,只有一个invoke方法,调用委托类的任何方法都是通过它的invoke方法来完成的。

你可能感兴趣的:(代理模式)