设计模式-结构模式之小结

来源:互联网 发布:螃蟹 知乎 编辑:程序博客网 时间:2024/06/04 18:26

更多请移步: 我的博客

目的

结构设计模式使的我们简单快速的建立类的层级及不同类之间的关系,明确不同层级间的责任和边界,让各个模块、系统间相互独立并很好的协作。

概览

Adapter模式

适配器的目的是使不兼容接口间的可正常进行协作,它允许我们新增接口。主要用来解决下面两个问题:

  • 接口间输入输出不匹配的问题,适配器在无法相互直接使用的接口间加入中间转换层,对数据格式进行转换,使接口间可以顺利协作。

  • 当你需要复用几个已经存在的类,但是它们缺少一些常用的功能。并且你无法在父类中添加这些功能,因为他是闭源或者被其他代码使用的。可以把这些缺少的功能放到新建的适配器中。

比如像OutputStreamWriter,它在构造方法中接收一个OutputStream作为内部变量。OutputStream并没有提供对String或者char类型的支持,于是OutputStreamWriter就出现了,OutputStreamWriter的基类定义了该接口要实现的功能,然后适配传入的字符串,但是最终还是把输出工作交给了OutputStream。

Adapter反对完全重新定义一个接口,原文没有对完全重新定义接口作出解释,但是它改变了原有接口,不过也不必太过于纠结于此。只要我们根据设计模式提供的思维方式把问题很好的解决就好。

Facade模式

门面让你为一个复杂的系统,类库或者框架提供一个简单的接口。可用在以下场景:

  • 需要一个简单但是功能有限的复杂子系统接口时

  • 把一个子系统构建成层级结构

上面两个场景在实际场景中很多,比如我们要使用第三方的类库,但是它并没有提供我们想要的接口,于是我们自己创建一个类来对它进行包装,并在这个类中管理三方库中一些对象的生命周期。

Decorator模式

装饰器让你在封装包涵对象原有行为的基础上增加新的行为。可用在以下场景:

  • 动态赋予某个对象行为并且不需要修改这个对象的代码

  • 不可能或者不合适通过继承来扩展对象的行为

装饰器是对已有接口的增强,它没有改变原有的接口,对使用者完全透明。比如我们会用Collections的synchronizedMap(Map

Proxy模式

代理模式为另外一个对象提供一个替身或者占位符来控制对它的访问。作用如下:

  • 懒初始化(虚拟代理)。当你有一个需要从文件系统,网络或者数据库加载数据的重量级对象时。

  • 访问控制(保护代理)。当一个程序有不同类型的用户并且你想阻止未授权用户对保护对象的访问。

  • 本地执行一个远程服务(远程代理)。当一个真实服务对象在远程服务器上时。

  • 缓存对象(智能引用)。当你需要混存客户端的请求并且管理它们的生命周期时(当结果比较重时)时。

  • 请求日志(日志代理)。当你需要保留一个服务对象的请求历史。

代理还分为静态和动态两种,动态代理常用在框架层面。上面列出的几个适用场景在Dubbo中有很好的体现,Dubbo代理了远程的服务,并对其做了缓存和访问控制等相关指标数据。了解Proxy模式去看下Dubbo源码是个不错的选择。

还是要从主要目的或者说意图上区分模式,Proxy并不像Decorator那样对接口做增强,也不像Adapter定义新的接口,但并不是Proxy做不了这些事情,它可以很轻松的对接口做增强,但那不是他的主要目的。PS:Proxy往往需要管理被代理对象的生命周期。

Composite模式

Composite模式让我们可以像树一样组合对象,并且允许客户端像操作单个对象一样和这些结构协作。使用该模式前一定要正确梳理清楚现有实体间抽象关系。

当有以下场景时,考量使用该模式:

  • 需要实现一个像树一样有着简单元素和容器的结构。

  • 客户端要统一处理简单和复杂的元素时。

之前接触一个店铺装修系统,用户使用定义好的基本组件组合出不同的网页效果。像系统中的输入框、图片、按钮等是基本的组件(像树的叶子),用户可以使用基本组件组成更复杂的组件放到自定义组件中(像一个树枝),自定义组件和基本组件遵循相同的接口,有着相同的属性和操作。这样,渲染引擎在渲染在将一个画面渲染的时候只需要关注当前画面用了那些组件,不必关心组件式什么类型的,只需要通过接口设置/获取自己需要的属性值即可。

组合模式和装饰模式很像,都依赖递归组合,但不同的是,装饰器用来增强接口而组合模式只是对接口结果做了合并。不必纠结于如此一点差别。就像黑猫VS白猫,捉到老鼠就是好猫。

Bridge模式

桥接模式分离一个巨大的类或者将一组关系相近的类分离成为两个独立的层次结构,抽象和实现,让各自可以独立开发。

这个模式提示我们,接口和实现必须分开。不过,现在企业级项目好像没有不这样做的。使用场景如下:

  • 有一个包含一些功能变种的大类(工作在几个不同的数据库服务上)

  • 需要在正交(独立)的维度扩展一个类(例子详见Bridge模式)

  • 需要在运行时改变实现(一个接口多种实现,比如:临时切换系统的支付通道)

Flyweight模式

享元来自于拳击界,表示轻量级选手(选手小于111磅)。这个舶来词形象表明这个模式的意图。通过在多个对象见共享对象状态的通用部分而不是让各个对象独自持有的方式来节约内存。我们在系统中常会定义一些常量供不通的对象使用,这也体现了享元模式的思想。在Java的核心类库中,像Integer、Boolean、Long和BigDecimal等都缓存了常用的(最大/小/0等)数值。

小结

翻译的文章对模式的解释比较浅显简单,可以让我们对模式有一个初步的认知,想要更深入理解和体会设计模式一方面离不开平时做项目时对业务和代码关于模式思考,尝试在编码时采用一些合适的模式,将理论运用到实践中,直观上体验模式带来的好处和问题;另一方面还是要深入读下《设计模式》这本书,来加深对模式的理解。个人认为模式的具体实现结构不必拘泥文中说的某种实现形式,它更重要的是要解决什么问题,以及我们可能会碰到什么问题,和优雅解决或者避免这些问题的方法。具体怎样去应用一个模式在单一介绍模式的文章中都有给出。

本次小结的这几种设计模式属设计模式中的结构部分,它告诉我们怎样比较合理的抽象数据结构间的层次和关系,也讲明了采用给出解决方法的会带来的一些问题。当然,一些场景的处理可能会有几种模式都可以适用,这时候就需要根据自己的主要意图、复杂性等方面来考量了,毕竟,复杂的代码让人讨厌。

TODO 目前对结构模式还是入门理解,会在看完《设计模式》中对结构模式的讲解后再来更新自己的这篇博文(2017年11月3日)。