设计模式之代理模式

序言

在看Retrofit源码时,我们会发现里面是使用了Java的动态代理的。 以前也接触过动态代理,平常不用,时间就久了就会慢慢淡忘。所以平常多总结,任何知识点也是如此。

作用

  1. 为其他的对象提供一种代理来控制这个对象的访问。
  2. 增强目标对象的功能

静态代理

开发者接口

public interface IDeveloper {
    void writeCode();
}    

Android开发者

public class AndroidDeveloper implements IDeveloper {

     @Override
	 public void writeCode() {
   		 System.out.println("Write Android Code");
	 }
}

测试

public class DevelopTest {

    public static void main(String arg[]){
    	IDeveloper developer=new AndroidDeveloper();
    	developer.writeCode();
	}
}

运行结果:

Write Android Code

现在麻烦的是,如果以后上级领导说,写代码前必须写注释写文档。 那我们就需要修改AndroidDeveloper这个类,这就不符合 “开闭原则”(对扩展开放,对修改关闭)。 所以我们可以创建个代理类,以不修改原始类中的代码来实现增强。

代理类

	public class DeveloperProxy implements IDeveloper {
	private  IDeveloper developer;

	public DeveloperProxy(IDeveloper developer){
    	this.developer=developer;
	}

	@Override
	public void writeCode() {
   		System.out.println("write Document or Note");
    	developer.writeCode();
	}
}

测试

public class DevelopTest {

	public static void main(String arg[]){
    
       IDeveloper developer=new AndroidDeveloper();
       DeveloperProxy proxy=new DeveloperProxy(developer);
       proxy.writeCode();
    }
}

运行结果:

write Document or Note
Write Android Code

可以看到我们在没有修改AndroidDevelop这个类,通过代理类来实现增强。

总结:

  • 被代理的类(AndroidDeveloper)和代理类(DeveloperProxy)实现了同一个接口,然后在代理类中引入AndroidDeveloper对象的引用。
  • 可以不改变被代理的类,来增强功能。

优点:

  • 代理使客户端不需操作 被代理的类(AndroidDeveloper), 只需要操作代理类(DeveloperProxy)就行了(解耦合)。

缺点:

  • 代理类跟被代理的类需要实现同样的接口,代理类跟被代理的类也实现了相同的方法,这样就出现大量的重复代码,接口增加一个方法,代理和被代理类就同时实现这个方法,增加代码维护的复杂度。
  • 代理类只能代理一种类型(IDeveloper)的对象 ,如果代理多种类型的对象,那肯定为每一种对象进行代理, 这种的情况静态代理就做不了了。
    即静态代理类只能为特定的接口服务,如果为多个接口服务,那必须建立多个代理类。

动态代理

开发者接口(需要动态代理的接口)

public interface IDeveloper {
    void writeCode();
}    

Android开发者(动态代理的实际对象)

public class AndroidDeveloper implements IDeveloper {

     @Override
	 public void writeCode() {
   		 System.out.println("Write Android Code");
	 }
}

代理方法被调用前后执行的操作 抽象出来。

public interface Before {

    public void before();
}


public interface After {

    void after();
}

创建自己的调用处理器,统一来处理和过滤一些消息。

public class InvocationHandlerImpl implements InvocationHandler {

private Object targetObject; //需要代理的对象

Before before; 

After after;

public Before getBefore() {
    return before;
}
public void setBefore(Before before) {
    this.before = before;
}

public After getAfter() {
    return after;
}

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

public  InvocationHandlerImpl(Object targetObject){
    this.targetObject=targetObject;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    /* 代理方法执行前 执行其他的操作*/
    if (before!=null){
        before.before();
    }
    Object result=method.invoke(targetObject,args);
    /* 代理方法执行后 执行其他的操作*/
    if (after!=null){
        after.after();
    }
    return result;
}
}

测试

public class DevelopTest {

public static void main(String arg[]){

    final IDeveloper p=new AndroidDeveloper();//需要代理的对象
    InvocationHandlerImpl invocationHandler=new InvocationHandlerImpl(p);
    invocationHandler.setBefore(new Before() {
        @Override
        public void before() {
            System.out.println("write Document or Note ");
        }
    });
    invocationHandler.setAfter(new After() {
        @Override
        public void after() {
            System.out.println("Review Code ");
        }
    });

    IDeveloper proxy= (IDeveloper) Proxy.newProxyInstance(p.getClass().getClassLoader(), new Class[]{IDeveloper.class},invocationHandler);
    proxy.writeCode();
}
}

运行结果:

write Document or Note
Write Android Code
Review Code

说明:

  • 当 proxy.writeCode()执行时, 会回调到这个InvocationHandlerImpl中的invoke方法。
  • InvocationHandler中的invode方法中的三个参数 1: 代理对象(proxy) 2: 方法对象(writeCode) 3:方法参数
  • newProxyInstance方法中的三个参数 1: 类加载器 2: 代理所实现的接口 3: 表示的是当动态代理对象调用方法时,会关联到这个对象上

JDK动态代理实现的步骤:

  • 创建被代理的类和以及实现的接口;
  • 创建一个实现接口InvocationHandler的类。 实现invoke方法;
  • 调用Proxy的newProxyInstance 静态方法,动态生成代理类;
  • 通过代理对象调用目标方法, 然后会转发到invoke方法;

总结:

  • 动态代理类在程序运行时动态生成,不需要写代理类源代码;
  • 被代理的类必须实现接口,代理的类没有实现接口的就不行(原因是Java不能进行多继承,只能实现多接口);
  • 基于Java内部的反射机制来实现;

Cglib 代理

Android开发者(动态代理的实际对象 不需实现任何接口)

public class AndroidDeveloperr {

	 public void writeCode() {
   		 System.out.println("Write Android Code");
	 }
}

代理方法被调用前后执行的操作 抽象出来。

public interface Before {

    public void before();
}


public interface After {

    void after();
}

创建自己的方法拦截器,统一来处理和过滤一些消息。

public class MethodInterceptorImpl implements MethodInterceptor {

Before before;

After after;

public Before getBefore() {
    return before;
}
public void setBefore(Before before) {
    this.before = before;
}

public After getAfter() {
    return after;
}

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

@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {

    if (before!=null){
        before.before();
    }
     Object result=methodProxy.invokeSuper(o,args);

    if (after!=null){
        after.after();
    }
    return result;
}
}

测试

public class DevelopTest {

public static void main(String arg[]){
    MethodInterceptorImpl methodInterceptor=new MethodInterceptorImpl();
    methodInterceptor.setBefore(new Before() {
        @Override
        public void before() {
            System.out.println("write Document or Note ");
        }
    });
    methodInterceptor.setAfter(new After() {
        @Override
        public void after() {
            System.out.println("Review Code ");
        }
    });
    Enhancer enhancer=new Enhancer();//创建增强类
    enhancer.setSuperclass(AndroidDeveloper.class);//设置继承被代理类
    enhancer.setCallback(methodInterceptor);//设置回调
    AndroidDeveloper androidDeveloper= (AndroidDeveloper) enhancer.create();//生成代理对象
    androidDeveloper.writeCode();//在调用代理方法时,会回调到我们设置的方法拦截器上所拦截
}
}

运行结果:

write Document or Note
Write Android Code
Review Code

说明:

  • MethodInterceptor中intercept 四个参数的含义 1:cglib生成的代理对象 2: 被代理的对象的方法对象 3: 方法的参数 4: 代理方法对 象

总结 :

  • 可以对类进行代理,不用基于接口代理;
  • 不能对final修饰的类和final方法进行代理(原因是final修饰的 不能被继承)

JDK和Cglib 区别

  1. JDK原生动态代理不需要引入任何的依赖,但是它是基于接口来进行代理;
  2. Cglib 是通过继承的方法来进行代理,不管目标对象有没有实现接口都能进行代理,但是无法代理final的情况。还有就是需要引入相应的依赖;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值