概述
设计模式总结,结构型设计模式篇.
结构型设计模式
结构型设计模式,主要是改变代码的结构来达到解耦的目的.使得代码更加容易维护和扩展.
代理模式
用一个代理对象来隐藏具体实现类的实现细节,通常用于在真实的实现逻辑中做增强操作(AOP).
代理指的是,对客户端隐藏真实的实现,由代理对象来负责接收客户端的所有请求.代理类只是代理,并不会完成实际业务的逻辑.
1 | //真实的接口 |
调用,通过多态的方式创建代理对象
1 | //创建代理对象 |
通过代理模式,可以将具体的实现方式隐藏起来,并且可以在代理类中实现切面编程的操作.
AOP其实就是动态代理的过程.在Spring中,我们自己不定义代理类,Spring会帮我们动态定义代理,然后帮我们把贴上@Before,@After,@Around注解的代码动态的添加到代理类中.
Spring动态代理
JDK动态代理.只能对实现了接口的类生成代理,而不能针对类.JDK动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理.
CGLIB动态代理.如果没有定义接口,Spring 会采用 CGLIB 进行动态代理,可以使用是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法.CGLIB动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理.
目标对象实现了接口 | 目标对象没有实现接口 |
---|---|
默认情况下会采用JDK的动态代理实现AOP | 必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换 |
可以强制使用CGLIB实现AOP |
设配器模式
将一个类的接口转换成客户希望的另外一个接口.适配器模式使得原本由于接口不兼容而不能在一起工作的那些类可以一起工作.《设计模式:可复用面向对象软件的基础》
设配器模式一般分为三种.一种是默认适配器模式,对象适配器模式,类适配器模式.
默认适配器模式(Default Adapter)
Apache的commons-io包作为默认适配器模式的例子.
此接口定义了很多方法,用于对文件或文件夹进行监控,一旦发生了对应的操作,就会触发相应的方法.
1 | public interface FileAlterationListener { |
这个接口的问题是抽象方法太多.假如要使用这个接口就必须实现这个接口里的所有方法,但是假如只需要这个接口中的一两个方法,还是得实现这个接口的所有方法.
因此需要一个适配器,先实现这个接口的.但是所有的实现方法都是空的.
1 | //创建一个适配器类来实现这个接口 |
调用的话,只需要自定义的类继承这个适配器就行了
1 | //只需要继承该适配器类,然后实现想要的方法. |
对象适配器模式
将一个对象当成另一个类的对象来使用.
将”鸡”当成”鸭”来使用,把”鸡”适配成”鸭”.因为现在”鸭”这个接口没有适合的实现类可以使用,所以需要适配器.
1 | public interface Duck { |
要把”鸡”当成”鸭”来用.”鸭”接口有现成的fly();方法,但是没有quack();方法.这个时候就需要适配器进行适配.
1 | //创建一个"鸡"适配器,要当成"鸭"来用,必须先实现"鸭"的接口. |
调用方式
1 | public static void main(String[] args) { |
适配器模式,解决的痛点.当我们需要一只”鸭”对象,但是我们只有一只”鸡”对象.此时就需要定义一个适配器.由这个适配器作为”鸭”的类,内部的实现方式还是通过”鸡”对象来实现的.
类适配器模式
1 | public interface Target { |
调用方式
1 | public static void main(String[] args) { |
因为SomeAdapter已经通过继承的方式获得了SomeThing的大部分方法.所有可以直接调用.
类适配 | 对象适配 |
---|---|
继承 | 组合 |
静态实现 | 动态实现,需要多实例化一个对象. |
使用较少 | 使用较多 |
适配器模式 | 代理模式 |
---|---|
将A包装成B,把A当成B来使用.A和B之间原本没有继承关系 | 增强原方法 |
桥梁模式
桥梁模式,主要是代码的抽象和解耦.
首先需要一个桥梁.定义一个接口,提供接口方法.
1 | //桥梁 |
通过实现类实现接口
1 | public class RedPen implements DrawAPI { |
定义一个抽象类,此类的实现类都需要使用DrawAPI接口
1 | public abstract class Shape { |
定义抽象类的子类
1 | //圆形 |
调用
1 | public static void main(String[] args) { |
通过最终的调用方式,可以知道桥梁模式的优点是解耦.通过把接口DrawAPI作为桥梁,而各种颜色画笔的类实现了该接口.通过定义抽象类,在抽象类中使用DrawAPI接口,同时图形(圆形或者长方形)的具体实现类又继承自该抽象类,在子类中通过子类的构造器调用父类构造器中的DrawAPI接口,就可以根据具体传入的参数(颜色画笔对象),获得颜色画笔的实现类.达到解耦的目的.
简而言之,就是通过定义一个接口.把该接口的实现类作为桥梁(参数)传入.通过继承图形的抽象类,定义需要具体的DrawAPI接口对象.