23中设计模式------代理模式(静态代理与动态代理)

简介

我们在做设计时,会遇到这样的问题:某一个类不希望直接被其他类引用,或者由于某种原因不能被引用,这个时候我们必须使用代理模式(Proxy Pattern)。

代理模式(Proxy Pattern),是指一个类代表另一个类的功能。它属于23种GOF设计模式的结构型设计模式 。在代理模式中,我们创建具有(包含)现有对象的对象,以便向外界提供功能接口。

使用场景

  • 可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能;
  • 出于安全角度考虑,需要屏蔽客户端直接访问真实对象;
  • 为了提升系统性能,对真实对象进行封装,从而达到延迟加载的目的

设计要素

  • 抽象角色(Subject):它的作用是定义一组行为规范。抽象角色一般呈现为接口(或抽象类),这些接口(或抽象类)中定义的方法就是待实现的。
  • 真实角色(RealSubject):实现了抽象角色所定义的行为。真实角色就是个普通的类,它需要实现抽象角色定义的那些接口。
  • 代理角色(Proxy):代表真实角色的角色。根据上面代理的定义,我们可以知道代理角色需要至少完成(或实现)真实角色的功能。为了完成这一使命,那么代理角色也需要实现抽象角色所定义的行为(即代理类需要实现抽象角色所定义的接口),并且在实现接口方法的时候需要调用真实角色的相应方法。

分类

我们有多种不同的方式来实现代理。如果按照代理创建和加载的时期来进行分类的话, 可以分为两种:静态代理和动态代理。

静态代理:静态代理是由程序员创建或特定工具自动生成源代码,然后对其编译。在程序运行之前,代理类.class文件就已经被创建,程序运行时直接调用即可

动态代理:动态代理是在程序运行时利用程序通过反射机制动态创建的,常见的动态代理创建方式有 jdk 动态代理和 cglib 动态代理两种。

代理实现

我们以一个人吃饭为例,在吃饭前和吃饭后需要两个增强功能:在吃饭之前要先洗手,吃饭以后漱口。我们分别用静态代理和动态代理的方式实现。

1、静态代理的实现

首先创建吃饭的接口 Eat ,接口中定义一个方法 startEat(),如下:

23中设计模式------代理模式(静态代理与动态代理)

定义一个类 EatChinesefood(吃中餐) ,该类是真正定义 startEat 具体内容的类,也就是 前面角色中的真是角色,在后面的代理中,会代理这个类。

23中设计模式------代理模式(静态代理与动态代理)

最后定义静态代理类 StaticProxy,这是真正代理 Eat 类的代理类,该类实现了 Eat 接口,并重写了 startEat 方法。在该类中,同时还定义了 两个增强方法 before() 和 after() ,在调用startEat方法前后,会调用这两个增强方法。

23中设计模式------代理模式(静态代理与动态代理)

在代理类中,调用 startEat() 方法前,会先调用 before() 方法,startEat() 方法后,再调用 after() 方法,因此,在代理类中,最终是 先洗手,然后吃饭,最后漱口,看看测试结果。

23中设计模式------代理模式(静态代理与动态代理)

测试结果与预期结果一致。

小结

静态代理模式虽然具有代理模式的有点,但是也有一些缺点,每次代理一个类,都需要写一个写一个对应的代理类,这回会造成系统设计中类的数目的增加,而且增加了代码的复杂度

2、JDK动态代理的实现

正因为静态代理实现过于复杂,并且会造成系统设计中类的数目的增加,因此引入的动态代理模式

我们还以吃饭为例,用动态代理模式实现,其中 接口 Eat 和 类 EatChinesefood(吃中餐) 不变,只改变代理类

23中设计模式------代理模式(静态代理与动态代理)

我们定义了一个动态代理类 DynamicProxy ,该类会封装被代理的类的相关接口调用的时候实际调用的是 invoke() 方法。 该类实现了 接口 InvocationHandler ,并定义了 before() 和 after() 方法,而真正的显现逻辑在 invoke() 方法中。

另外,我们定义个工厂类 BeanFactory ,该类是真正产生代理类的地方

23中设计模式------代理模式(静态代理与动态代理)

在这个类中,我们通过 Proxy 的代理方法 newProxyInstance 代理出一个类测试结果如下

23中设计模式------代理模式(静态代理与动态代理)

小结

动态代理可以代理任何一个实现了某一接口的对象,它有效的避免了静态代理模式中带来的复杂度的问题,同时也不需要写过多的类,因此,在实际开发当中,动态代理使用的是最多的一种代理模式。

结束语

代理模式是23种设计模式的一种非常重要的模式,它在开发中运用的非常广泛Spring 的 AOP 使用的就是动态代理模式,由于 jdk 的动态代理模式也会有一些其他的问题(被代理的类必须实现某一接口),Spring 的 AOP 是用的是 JDK动态代理 和 cglib 动态代理相结合的方式。由于篇幅限制,cglib 会在后面的章节中单独讲。

创作不易,转载请声明,如有疑问、意见和建议,请在下方评论区留言!


分享到:


相關文章: