文章目录
源码链接:https://github.com/ouyangxizhu/design_pattern.git

二、结构型模式
1. 外观模式(门面模式)
com.ouyangxizhu.design.pattern.structural.facade
定义
提供了一个结构来访问子系统中的一群接口。
这个外观结构封装了子系统之间的调用逻辑,调用顺序。比如购物,用户只关注我能不能买成功(下单功能),至于怎么减库存,怎么生成订单,怎么物流配送都不需要知道。
适用场景
- 当子系统越来越复杂,增加外观模式提供简单接口调用。
- 构件多层系统结构,利用外观对象作为每层的入口,简化层间调用。
优点
- 简化了调用过程,无需深入了解子系统,防止带来风险。
- 减少系统依赖,松散耦合。
- 更好的划分访问层次。
- 符合迪米特法则,即最少知道原则。(调用者只和外观类有关系)
缺点
- 增加或者扩展子系统容易引入风险。
- 增加或者扩展子系统不符合开闭原则。(可以使用抽象外观类,或者采用继承实现)
源码
都是对jdbc的封装。
org.springframework.jdbc.support.JdbcUtils#closeConnection(封装Connection的close()等)
org.springframework.jdbc.support.JdbcUtils#getResultSetValue(java.sql.ResultSet, int, java.lang.Class<?>)
org.apache.ibatis.session.Configuration#newParameterHandler等handler
tomcat的requestFacade类(实现HttpSevletRequest接口)StatementFacade等
外观模式和中介者模式
外观模式关注外界和外观类(封装子系统)之间的交互。
中介者模式关注子系统内部之间的交互。
外观模式和单例模式
可以把外观模式的外观对象做成单例使用。
外观模式和抽象工厂模式
外观对象可以通过抽象工厂获得子系统的实例。子系统可以对外观实例屏蔽细节。
2. 装饰者模式
com.ouyangxizhu.design.pattern.structural.decorator
定义
装饰者有一个有参构造器,该参数为被装饰者,只需要在调用被装饰者前或者后添加逻辑,就可以进行装饰。可以多层装饰。
在不改变原有对象的基础上,将功能附加到对象上。提供了比继承更有弹性的替代方案(扩展原有对象功能,装饰者是运行期间添加,并且可以自由组合顺序的装饰,继承是编译过程添加的。装饰者会继承被装饰的对象)一般装饰者会有自己父类的属性,可以在构造器的时候注入。
适用场景
- 添加一个类的功能,或者给一个类添加附加职责。
- 动态的给一个对象添加功能,这些功能可以再动态撤销。
优点
- 继承的有力补充,比继承灵活,不改变原有对象的基础上给对象扩展功能。
- 通过使用不同的装饰类以及这些装饰类的排列组合,可以实现不同的效果。
- 符合开闭原则。
缺点
- 会出现更多的代码,更多的类,增加程序的复杂性。
- 动态装饰,多层装饰时会更加复杂。排查会比较困难。
源码
java.io.BufferedReader#BufferedReader(java.io.Reader, int)
java.io.BufferedInputStream#BufferedInputStream(java.io.InputStream, int)
java.io.FileInputStream#FileInputStream(java.io.File)
org.springframework.cache.transaction.TransactionAwareCacheDecorator
org.springframework.session.web.http.SessionRepositoryFilter.SessionRepositoryRequestWrapper
org.apache.ibatis.cache.decorators
装饰者模式和代理模式
装饰者模式关注在一个对象上动态的添加方法,代理模式关注对对象的控制访问。
代理对象可以对客户隐藏对象的具体信息,使用代理类的时候会创建被代理对象的实例,装饰者模式通常将被装饰者作为参数传给装饰者的构造器。
装饰者模式和代理模式都可以实现前置和后置通知,但是装饰者不能环绕通知,代理模式可以。
装饰者和适配器模式
都是wrapper,装饰者和被装饰者实现相同的接口,或者装饰者是被装饰者的子类,适配器一般是实现不同的接口。
3. 适配器模式
com.ouyangxizhu.design.pattern.structural.adapter
定义
将一个接口转换为客户需要的另一个接口。是原本接口不兼容的类可以一起工作。
适用场景
- 已经存在的类,他的方法和需求不匹配时(方法结果相同或相似)。
- 不是软件设计阶段考虑的设计模式,是随着软件的维护,由于不同产品,不同厂家,造成功能类似为接口不同情况下的解决方案。
优点
- 能提高类的透明性和复用,现有的类复用但不需要改变。
- 目标类和适配器类解耦,提高程序扩展性。
- 符合开闭原则。
缺点
- 适配器编写过程需要全面考虑,可能会增加系统的复杂性。
- 增加系统代码的可读难度。
扩展
对象适配器模式,符合组合复用原则。使用委托机制。适配器类包含被适配者的属性。(组合)
类适配器模式,使用类继承。
源码
java.io.InputStreamReader
javax.xml.bind.annotation.adapters
org.springframework.aop.framework.adapter.MethodBeforeAdviceAdapter
org.springframework.web.servlet.HandlerAdapter
org.springframework.web.servlet.DispatcherServlet#initHandlerAdapters
适配器模式和外观模式
外观模式是定义了一个新的接口,适配器模式是复用原有的接口。外观的规模更大。
4. 享元模式
com.ouyangxizhu.design.pattern.structural.flyweight
定义
提供了减少对象数量,从而改善应用所需的对象结构的方式。应用共享技术有效的支持大量细粒度的对象。
适用场景
- 常常应用于系统的底层开发,以解决系统的性能问题。
- 系统有大量的相似对象,需要缓冲池的场景。
优点
- 减少对象创建,降低内存中的对象数量,降低系统的内存,提高效率。
- 减少内存之外的其他占用。比如new对象需要一定的时间。
缺点
- 区别内部和外部状态,关注线程安全问题。
- 使程序系统的逻辑复杂化。
内部状态和外部状态
内部状态指在享元对象的内部,不会随着环境变化的共享部分。
外部状态指在享元对象的外部,会随着环境变化,不能共享。
源码
字符串常量池,连接池。方法区中。文件句柄,窗口句柄。Integer的缓存。
org.apache.ibatis.binding.MapperProxy#cachedMapperMethod
享元模式和代理模式
可以用享元模式来代替代理里面创建的对象。
享元模式和单例模式
IOC容器就是两者结合的例子。
5. 组合模式
com.ouyangxizhu.design.pattern.structural.composite
定义
将对象组合成树形结构以表示”部分-整体“的层次结构。组合模式使客户端都单个对象和组合对象保持一致的方式处理。(部分和整体继承同一个类或实现相同的接口(一致的对象类型,传入的参数是父类)对整体和部分进行定制化处理(在各自对应的类中))
适用场景
- 希望客户端可以忽略组合对象和单个对象的差异时。
- 处理一个树形结构。
优点
- 清楚地定义分层次的复杂对象,表示对象的全部或者部分层次。
- 让客户端忽略了层次的差异,方便对整个层次结构进行控制。简化客户端代码。(要不然客户端得判断类型)
- 符合开闭原则。
缺点
- 限制类型会比较复杂。
- 让设计变的更加抽象。
源码
java.util.ArrayList#addAll(java.util.Collection<? extends E>)注意传入的参数是父类对象。
org.apache.ibatis.scripting.xmltags.SqlNode及其实现类。(各种sql都解析成SqlNode)
组合模式和访问者模式
可以用访问者模式访问组合模式的递归结构。
6. 桥接模式
com.ouyangxizhu.design.pattern.structural.bridge
定义
将抽象部分与他的具体实现部分分离,使他们都可以独立的变化(通过组合方式建立两者之间的关系,而不是继承)将继承关系变为关联关系。相应的方法一定要委托给被组合的对象
适用场景
- 抽象和具体实现之间增加更多的灵活性
- 一个类存在两个或者多个独立变化的维度。且这两个或者多个维度都需要进行独立的扩展。
- 不希望继承,继承会使类的个数增加。
优点
- 分离抽象部分和具体实现部分。一定程度可以避免子类剧烈增加的后果。
- 提高系统可以扩展性。
- 符合开闭原则
- 符合合成复用原则。
缺点
- 增加系统的理解和设计难度。
- 需要正确的识别出系统中两个独立变化的维度。
源码
java.sql.DriverManager和java.sql.Driver。
java.sql.DriverManager#getConnection(java.lang.String, java.util.Properties)的java.sql.Connection 可以在不同数据库中转化。
桥接和组合模式
桥接模式注重平行级别间类直接的组合。组合模式强调部分和整体间的组合。
桥接模式和适配器模式
适配器改变接口,桥接模式把类的抽象和具体实现分离开。
7. 代理模式
com.ouyangxizhu.design.pattern.structural.proxy
定义
为其他对象提供一种代理,以控制对这个对象的访问。代理对象在客户端和目标对象之间起到中介的作用。
适用场景
- 保护目标对象
- 增强目标对象
优点
- 可以将代理对象和被调用的目标对象分离
- 一定程度上降低耦合度,扩展性好
- 保护目标对象
- 增强目标对象
缺点
- 造成系统设计中类的数目增加(代理类)
- 有代理类,会造成请求处理的速度变慢
- 增加系统复杂度。
静态代理和动态代理
静态代理在编译阶段确定被代理的类,JDK动态代理代理接口。CGLIB针对类(生成被代理类的子类,重写方法,所以final的不能被代理)速度:JDK动态代理>CGLIB。动态代理是运行时确定的,自己传的,因此代码可以复用。
源码
org.springframework.aop.framework.ProxyFactoryBean(核心方法getObject())。
org.springframework.aop.framework.JdkDynamicAopProxy
org.apache.ibatis.binding.MapperProxyFactory
org.apache.ibatis.binding.MapperProxy
其实mybatis的dao接口就是通过代理模式实现调用的
来源:https://blog.csdn.net/qq_37886086/article/details/99624942