设计模式(四)结构型模式
前言
结构型设计模式,主要研究:
- 主要有哪些场景使用结构型设计模式;
- 每种场景应该使用何种设计模式;
- 以程序中的功能为核心,研究程序功能的组织结构。所以这一章,我们要把“功能结构”作为研究的核心。
下面分别对几种结构型模式加以说明。
1. 适配器模式
示例:适配器模式
使用场景
想要在系统中添加某个功能,类似的功能在其他项目中已经实现,而且经过分析,旧的接口可以经过适当的封装,转换成新的适用于当前系统的接口。这样可以最大程度地复用已有的模块。
原理
通过适配器将已有功能的旧的接口,转换为新的接口,从而实现使已有的功能为新的系统服务的目的。
不适用的情况
以下情况下,不要使用适配器模式:
- 旧的接口无法转换成新的接口;
- 写适配器的工作量几乎可以重写所需的功能时。
使用须知
适配器模式其实是一种取巧的做法,在使用时需要慎重考虑。已有功能通过适配器集成到新的系统后,如果出现问题或者需要进行功能扩展,其维护成本是一个需要考虑的问题。例如,已有功能是否使用了过时的技术,或者资料不全,都可能成为项目的风险所在。
本质
适配器模式本质上是通过将一接口封装成另一种接口,实现了模块功能复用。
2. 桥接模式
示例:桥接模式
使用场景
桥接模式是少用继承,多用组合的第一例。
拿菜鸟教程中的例子来说,假如我们现在要实现圆类,包括红色圆和绿色圆两种圆。
首先容易想到的方法是,先写一个圆基类,并添加一个虚(virtual)的绘制函数。然后分别派生出红色圆类和绿色圆类,在子类中分别重新实现绘制函数,将圆绘制成指定的颜色。
在这种简单的例子中,使用继承是没什么问题的。但是假如圆基类还有一个虚函数,此虚函数用于对圆进行旋转。旋转分为两种,顺时针和逆时针旋转。我们想要四种类型的圆:
- 顺时针旋转的红色圆
- 顺时针旋转的绿色圆
- 逆时针旋转的红色圆
- 逆时针旋转的绿色圆
如何使用继承来实现呢?难道要派生出四个子类吗?如果还有其他功能组合呢?要多少个类呢?这样下去无疑会导致“类的数量爆炸”问题。
原理
结构型模式是研究程序功能组织方法的设计模式。当程序中需要对几种功能相互组合时,应该用组合,不要用继承。
桥接模式下,对于每个功能,应该提取出一个接口类,这个接口类可以有不同的实现。而代表不同的功能接口,可以作为主体类(此例中为圆类)的成员变量,放在一起。需要什么功能,就new哪种接口子类,保存在接口变量中,这样就可以把不同的功能组合起来。
这样一来,类的数量会保持在最低水平。
相对于继承,桥接模式相当于把主体类中的每个虚函数都单独提取出来,构成 一个接口类。这个接口类连接了具体实现和主体类,所以这个模式叫桥接模式。这个名字其实不是很能反映此模式的内涵,其实叫“功能组合模式”更为贴切。
可能有的小伙伴会说,上面的功能其实用C语言实现不是更简单吗?
- 用一个结构体代表圆,有半径、边框宽度等属性;
- 每种功能就是一个函数,参数为圆的结构体。
这不就完成了吗?是的!
这个场景下,确实使用C语言实现更简单,不需要使用C++面向对象的任何特性即可实现。可以看出,C++的面向对象的特性,并不是万能的,并不是在所有情况下都是最优的,甚至有时候不如C语言简单直接。从另一个角度说明,大家在面向对象编程的时候,不要把自己的思维局限于面向对象,面向对象思想在一些时候,是不如面向过程的,甚至会把功能结构复杂化,设计到最后导致代码难以维护都是有可能的。
使用须知
桥接模式会导致代码中存在设计模式的代码,会增加代码的理解难度。相对来说,积极作用还是远大于副作用的。
本质
桥接模式的本质是:
如果项目中出现了功能组合的场景,使用继承封装功能是错误做法,要把功能单独提取出来分别封装好以后,再进行组合。
3. 过滤器模式
示例:过滤器模式
使用场景
现有一组对象,我们想要根据不同的过滤条件,筛选出符合条件的一部分对象。
一般写法
最简单粗暴的方法是,在需要进行筛选过滤的地方,直接遍历对象数组,在循环体内进行条件判断。这种写法的优点是简单直接,缺点是如果有多个地方需要使用筛选过滤功能,则需要在多个地方编写重复的代码,这会降低代码的复用性和可维护性。
推荐写法
使用过滤器模式,把筛选功能封装起来使用即可。接口也很好定义,输入对象数组,输出符号条件的对象数组。
本质
过滤器模式的本质是:
当需要从一组对象中过滤出一部分符合条件的对象时,可以考虑将每种过滤功能都封装为一个类,提高代码复用性和可维护性。
4. 组合模式
示例:组合模式
组合模式是一种树形的对象组织结构,在建造者模式已有相关说明,这里不再赘述。
5. 装饰器模式
示例:装饰器模式
使用场景
装饰器模式的研究对象有两个:
- 已有功能
- 扩展功能
当我们需要扩展一个类的功能,但是又不想直接在此类上进行改动时,一般的做法是使用继承来实现。继承出来的子类具有父类的属性和方法,在父类基础上可以添加新的功能。
除了继承,还可以使用装饰器模式。装饰器模式是指,新建一个扩展类,将被扩展类的对象作为扩展类的成员变量保存,在扩展类中,操作被扩展类,实现新的方法和功能。
简单来说,装饰器模式就是新建一个类把已有类的功能包装起来,实现新的功能。
使用须知
装饰器模式和继承各有优缺点,使用时要加以权衡,选择最优的方案。
本质
从本质上说:
装饰器模式通过将已有功能作为成员变量整个封装(包装)起来,扩展的新功能,和已有功能耦合最小,互不影响。
6. 外观模式
示例:装饰器模式
本质
这个模式比较简单不再赘述。其本质是:
将已有功能封装起来,提供更易于使用的接口,屏蔽更多实现细节,等于是加了一个中间层。
7. 享元模式
示例:享元模式
按照我们的分类,此模式应该属于创建型模式。它是借助工厂模式来实现一个对象缓冲池,减少对象数量 ,加速创建速度。这里不再赘述。
8. 代理模式
示例:代理模式
应用场景
代理模式就是中介模式。例如我们想要租房,原本租房是发生在租客和房东之间的事务,但中介的出现,虽然会有一定的费用(损耗),但是整个过程的推进会更加顺利。代理模式,用来将两个比较难以直接沟通的功能主体关联起来,实现二者交互。
使用须知
和租房找中介一样,只有在必要的时候才找,否则就是浪费资源,只有在非用不可的时候才建议使用代理模式。
本质
代理模式的本质是:
代理模式封装了沟通所需的所有功能,将两个难以直接沟通的功能主体连接起来,起到了桥梁作用。
结语
结构型模式,就是以功能为核心,研究功能转换、功能调用、功能组合、功能封装等各种情形下,将哪些功能封装到哪些类中,更加高效地实现需求,提升代码的可维护性。
设计模式(四)结构型模式相关推荐
- 备战面试日记(3.3) - (设计模式.23种设计模式之结构型模式)
本人本科毕业,21届毕业生,一年工作经验,简历专业技能如下,现根据简历,并根据所学知识复习准备面试. 记录日期:2022.1.9 大部分知识点只做大致介绍,具体内容根据推荐博文链接进行详细复习. 文章 ...
- 设计模式之结构型模式(5种)
目录 结构型模式(Structural Pattern):怎么构造一个对象(行为.属性) 一.适配器模式 二.桥接模式(Bridge) 三.装饰者模式 设计模式在JAVA I/O库中的应用 案例 使用 ...
- JAVA23种设计模式(2)-结构型模式7种
JAVA23种设计模式(2)-结构型模式7种 把类结合在一起形成更大的结构 适配器模式(adapter) 一句话:将一个类的接口转换成另一种接口.让原本接口不兼容的类可以兼容 这是平时比较常见的一种模 ...
- 设计模式 之 结构型模式
设计模式 之 结构型模式 模式 & 描述 包括 结构型模式 这些设计模式关注类和对象的组合.继承的概念被用来组合接口和定义组合对象获得新功能的方式. 适配器模式(Adapter Pattern ...
- 组合模式(Bridge Pattern) – 设计模式之结构型模式
组合模式(Bridge Pattern) – 设计模式之结构型模式: 目录 组合模式(Component Pattern) 类图 例子1: 过程: 类图: 代码: 抽象组件:PlayerComposi ...
- 设计模式(17)-----结构型模式-----外观设计模式
假如你现在还在为自己的技术担忧,假如你现在想提升自己的工资,假如你想在职场上获得更多的话语权,假如你想顺利的度过35岁这个魔咒,假如你想体验BAT的工作环境,那么现在请我们一起开启提升技术之旅吧,详情 ...
- 设计模式3——结构型模式
结构型模式描述如何将类或对象按某种布局组成更大的结构,它分为类结构型和对象结构型模式,前者采用继承机制来组织接口和类,后者采用组合或聚合来组合对象. 由于组合关系或聚合关系比继承关系耦合度低,满足&q ...
- 设计模式:结构型模式-桥接、外观、组合、享元模式
结构型模式 结构型模式描述如何将类或对象按某种布局组成更大的结构.它分为类结构型模式和对象结构型模式,前者采用继承机制来组织接口和类,后者采用组合或聚合来组合对象. 由于组合关系或聚合关系比继承关系耦 ...
- 设计模式_结构型模式学习
其中,单例模式用来创建全局唯一的对象.工厂模式用来创建不同但是相关类型的对象(继承同一父类或者接口的一组子类),由给定的参数来决定创建哪种类型的对象.建造者模式是用来创建复杂对象,可以通过设置不同的可 ...
- 设计模式之结构型模式
结构型模式 一.适配器模式 (一)定义:适配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁,它结合了两个独立接口的功能.这种模式涉及到一个单一的类,该类负责加入独立的或不兼容 ...
最新文章
- python使用符号#表示单行注释-【经济金融及Python应用讲义】Python编程规范之注释...
- java抓取网页css,Java 读取网页Html资料
- 具有JDK 12精简数字格式的自定义精简数字模式
- Error: Cannot find module 'webpack-cli'--解决方案
- oracle表压缩比,oracle的compress 特性介绍
- hdf5 matlab,通过MATLAB将矩阵数据写入HDF5文件中的每个数据类型成员
- Java程序员都要懂得知识点:反射
- jzoj4313 电话线铺设(最小生成树+最近公共祖先)
- kali64位下载怎么是AMD_电脑达人速更 NVIDIA 显卡和 AMD 显卡驱动程序又双叒叕更新啦!...
- 【机器学习实战】垃圾分类快速理解机器学习中的朴素贝叶斯(Naive Bayes)
- JNI 本地方法注册
- native2ascii编码转换
- 通过QQ 2012 客户端协议获取clientkey的0x91数据包分析
- python创建excel并冻结首行
- QT编译程序出现[ui_Widget.h] Error 1
- 将一个大文件分割为若干个小文件的方法
- 浅谈Docker的安全性支持(上篇)
- Java实现递归查询树结构
- After Effects Guru: Mastering the Timeline After Effects Guru:掌握时间轴 Lynda课程中文字幕
- 大数据营销--中关村大数据产业联盟秘书长赵国栋访谈
热门文章
- APP里如何添加本地文本
- ViewGroup之getScrollX()
- 判断一个数是不是整数
- WPF指南之XAML概述
- PAT1130. Infix Expression (25) 中序遍历
- nodejs python 通信_Nodejs环境实现socket通信过程解析
- 带孩子们做环球旅行的读后感_父母带孩子做心理咨询,需要注意哪些事项?
- 装mysql最后一步没响应_解决MySQL安装到最后一步未响应的三种方法
- threejs坐标转换
- ClassCastException:AdaptiveIconDrawable cannot be cast to BitmapDrawable