百度飙风算法 小网站,修邦建设网站,wordpress后台加载慢,网站文章页图片大全前言
在上一篇结构型模式中#xff0c;我们以功能为基本单位#xff0c;研究了一些设计模式#xff0c;用于实现功能转换、功能组合、功能封装等目的。
我们知道#xff0c;面向对象编程有两个核心元素#xff1a;对象、对象间通信协作。从面向对象的角度看#xff0c;…前言
在上一篇结构型模式中我们以功能为基本单位研究了一些设计模式用于实现功能转换、功能组合、功能封装等目的。
我们知道面向对象编程有两个核心元素对象、对象间通信协作。从面向对象的角度看任何系统和功能都是由一个个对象相互分工合作实现的。推而广之很多系统也都是这样组织和运行的。
本章的设计模式列举了通用场景下常用功能机制的经典实现方法讲解了经典实现中是如何高效组织对象、控制对象协作交互的具有很好的参考价值。 责任链模式
示例https://www.runoob.com/design-pattern/chain-of-responsibility-pattern.html
原理说明
责任链模式就是把程序处理对象前后排列起来形成一条处理线。处理线上需要被处理的信息在处理线上向下传递任何一个节点都可以随时中断传递。
使用场景
GUI系统中的事件传递机制在Javascript中叫做事件冒泡是责任链模式最典型的应用之一。
当某一事件发生时最顶层GUI对象会首先收到事件但是它先不处理而是依次交给命中的子GUI对象处理。当子GUI对象返回为False时表示事件未被接收此时父GUI对象才真正对发生的事件进行业务处理。
可以看出事件传递机制是一种增强版的责任链模式它的节点处理权经历了向下和向上的双向传递过程。
总结当项目中一个数据对象需要被多个处理对象进行处理时可以将处理对象链接起来然后把数据对象传递给头节点随着处理的进行数据对象的处理权会在处理链中流动从而完成整个处理过程。
使用须知
责任链模式结构适用于需求固定的场景用于实现简单高效的处理机制。假如需求不断变化而且功能很复杂那么用责任链模式很可能就无法胜任了需要采用新的高复杂度的设计。例如如果想要数据对象在所有处理对象中根据状态来实现跳转可以选择使用状态机等其他方案来实现。
本质 责任链模式从本质上说是一种简单的线性对象组织方式优点是简单高效。它将处理对象封装集合在一起实现对数据的集中处理实现了处理对象的高内聚降低了处理对象和数据对象的耦合。 命令模式
示例https://www.runoob.com/design-pattern/command-pattern.html
使用场景
想要实现撤销、重做、事务等功能可以使用此设计模式。通常在编辑器、数据库中有此类功能需求。
原理说明
命令也就是请求或者叫调用。命令模式要求将请求参数和请求相关的方法封装在一起。
请求对象中封装了实现“撤销”、“重做”、“事务”功能所需要的所有信息实现了关联信息的高内聚所以可以实现我们想要的功能。
例如可以在请求对象中保存修改之前的值、修改之后的值。利用修改之前的值可以实现“撤销”功能利用修改之后的值可以实现“重做”功能。如果将所有请求对象都记录下来并按照先后顺序排列起来形成“撤销重做”堆栈这样就可以实现连续的“撤销”、“重做”。“事务”则是“撤销”与“重做”的结合体正常执行流程等同于“重做”发生错误需要回滚等同于“撤销”。
如果不采用这种方式会导致实现这些功能的信息分散在源码中多个地方或者已经丢失没有保存就无法实现“撤销”、“重做”、“事务”功能。
同时实现请求参数高内聚也可以很方便地将它们保存到磁盘上保存到文件的过程叫做“序列化”从文件中读取的过程叫“反序列化”。这里的序列指的就是二进制流。
Qt中与命令模式相关的部分是Undo Framework里面有示例项目不熟悉的同学可以抽点时间看一看。
本质 命令模式的本质是将请求相关的信息和操作封装在一起实现信息的高度内聚可以方便地实现“撤销”、“重做”、“事务”等功能。 解释器模式
示例https://www.runoob.com/design-pattern/interpreter-pattern.html
原理说明
顾名思义解释器模式是用来实现解释器的。 解释器是这样一个程序解释器以符合语法的文本为输入解释输入内容完成一定的计算功能。文本可以在程序运行时动态加载动态解释、动态执行。
使用场景
实现简单的解释器命令行程序如ping命令、cd命令等 实现复杂的解释器脚本语言解释器如pythonluajavascript计算器。
我们知道在GUI图形用户界面被发明之前人类和程序之间的交互是通过敲命令行实现的缺点是使用难度较大门槛较高。 在GUI发明以后交互更加友好电脑更加易于使用了所以也更加普及了。
但是GUI交互的缺点在于不够灵活对参数的控制粒度不够细致。例如现在大多数开发者都使用集成开发环境来开发软件一般情况下都使用默认参数比较方便。但是如果你想要更改某些编译选项可能还是需要直接修改底层的编译命令。命令相对于GUI元素更加灵活过于灵活的地方用GUI比较难于实现例如组合、递归、跳转等等。在这些场景下使用解释器是非常合适的。但是通常情况下这个模式并不常用。
本质 解释器模式的本质是它提出了一种基于文本的、比GUI更加灵活的对外提供功能服务的方式。为了实现这种交互功能需要以命令文本为参数把解释、执行的过程封装在解释器内部。 迭代器模式
示例https://www.runoob.com/design-pattern/iterator-pattern.html
使用场景
在需要多次遍历同一个数据集合的时候为了少些一些for或者想要把遍历过程封装起来降低耦合就可以使用迭代器模式。这个模式非常常用。
原理说明
迭代器就是一个专门用来遍历数组的类。它只需要实现两个接口hasNext()、next()。 hasNext()接口用于控制循环何时停止next()接口用于取出当前位置的数据元素并将遍历指针指向下一个元素。 当然构造迭代器对象的时候需要将数据集合传递给迭代器让迭代器知道要遍历哪些数据。
原本需要用for循环来遍历的代码现在通过封装提取出了“遍历”这一功能所需要的必要信息定义了两个接口把不必要暴露的信息封装在了迭代器中妥妥的实现了解耦。
本质 迭代器模式的本质是为了更好地实现遍历功能新建一个迭代器类专门封装底层的遍历过程暴露两个简单的接口实现遍历功能使用者和底层遍历过程的解耦。 中介者模式
示例https://www.runoob.com/design-pattern/mediator-pattern.html
原理说明
中介者模式是指在原本直接通信的对象之间添加一个通信中间层使对象间通信变为间接通信降低对象间的耦合。
此模式和代理模式基本思想上是一致的。二者的区别是代理模式是通过加一个中间层来实现两个原本很难交互的功能主体实现顺畅交互中介者模式是为了降低对象间通信时的耦合而提出的为的是提高代码的可维护性。
使用场景
比较大的项目中会用到一般存在于某些框架中。因为大的项目中对象繁多通信也比较复杂适合使用中介者模式。
在大的项目中一般会有一个全局的通信管理器任何对象都可以使用通信管理器提供的接口将自己注册为某一个具有唯一ID消息的发送者和接收者。这样发送者只需要发送消息不需要管谁来接收不需要拥有发送者的实例指针发出消息后已注册的接收者都会收到消息。接收者不需要管信号是谁发的即不需要拥有发送者的实例指针。
所以中介者模式也可以叫“通信中介模式”。
本质 中介者模式的本质是对于信号接收者来说中介者模式将信号发送者封装了起来对信号发送者来说中介者模式将信号接收者封装了起来实现了通信双方的互相解耦。这是一种优化对象间通信协作的一种设计模式。 备忘录模式
示例https://www.runoob.com/design-pattern/memento-pattern.html
使用场景
这个模式和状态存档功能是绑定在一起的。为了在程序中实现状态存档功能可以使用备忘录模式。
使用说明
原例子中有三个类个人觉得没有必要这里我们简化成两个类即备忘录模式中有两个类状态对象类和状态对象管理类。 状态对象类是状态字段是集合并提供了存取接口状态对象管理类负责组织和保存状态对象。当然实际实现中可以根据需求增加类配合使用完成状态保存恢复。
本质 备忘录模式专注于实现程序中状态的存档功能它封装了状态的保存与恢复过程使用者无需关心具体细节。 观察者模式
使用场景
当一个对象会影响到其他多个对象时即当对象间存在一对多关系时使用观察者模式。 一般应用于单向通知的场景如GUI中鼠标事件、按键事件、窗口事件通知。使用Qt中的信号槽机制可以实现此模式。
使用说明
“一”是指发生变化的那个对象“多”是指需要获取此变化通知的对象组。其中变化消息是单向地由“一”到“多”传递的。如果不是单向的或者对象间不是一对多的关系更加复杂就需要重新思考其他对象间通信模型。
如果不使用此模式可能会导致观察者不能动态增加或删除可能会造成发送者的业务代码和接收者的响应代码混在一起耦合严重。
使用此模式需要为观察者设计一个基类并设计一个接收通知的接口所有观察者需要实现通知接口所有观察者指针可以保存在队列中实现动态增删。
本质 观察者模式本质是为了实现对象的“一对多”单向通信是一种通信模式。它将消息发送者和接收者独立封装实现了二者的解耦。 状态模式
使用场景
状态模式用于实现状态机。 如果一个程序功能中存在某些状态在一定情况下这些状态可以互相转换并且在转换前后需要作出对应的操作这种情况下使用状态机来实现就非常合适。
使用说明
如果不使用状态机状态模式一般的实现方法是使用一连串的if-else或者使用长长的switch-case来实现。这样做的缺点一方面状态判断不够高效另一方面是业务代码集中在一块不好维护。
使用状态机每个状态都是一个类相关的业务代码分布到各自的状态类中能够实现不同的状态及与状态相关的业务代码解耦。同时某个状态和下一个状态是关联好的在状态切换时效率更高不需要执行长长的判断。
Qt中已实现状态机框架The State Machine Framework在此框架下我们可以更加专注于业务实现而不是状态机本身的技术细节。
本质 状态模式的本质是将不同的状态封装成不同的类实现状态与状态间解耦。 空对象模式
示例https://www.runoob.com/design-pattern/null-object-pattern.html
使用场景
使用基类保存子类对象通常有两种做法
用基类指针保存子类对象用基类对象保存子类对象。
第一种方法用指针是基本方法但是指针用起来要非常小心要考虑内存释放的问题。此时空对象就可以用空指针表示。 第二种方法用基类对象保存子类对象这种方法使用起来相对省心不用与指针打交道使用者不用直接管理内存。例如Qt中的Qt XML C Classes类的设计就是采用这种方式设计的。这种情况下因为不使用指针就需要使用空对象来代替空指针。
使用说明
可以仿造Qt XML中的类进行设计。一般需要提供isNull()接口对象类型转换接口等。
本质 空对象模式的本质是使用对象化的形式封装指针和内存操作针对实现对象的保存实现0指针设计一般用在子类父类的设计中。 策略模式
使用场景
策略模式和桥接模式类似用于实现功能切换与组合。二者区别在于策略模式专注于一个功能的不同实现方式桥接模式专注于多个功能之间的组合。
使用说明
将功能抽象成单独的类功能切换只需要切换不同的功能子类即可同一个功能需要实现同一个功能接口。
本质 策略模式的本质是保持功能接口不变将不同的功能实现策略封装成子类可以实现功能策略的切换。 模板模式
示例https://www.runoob.com/design-pattern/template-pattern.html
使用说明
模板模式应该是我们最熟悉的。 这里的模板就是接口类接口类定义了使用者和功能提供者之间交互的函数列表。子类负责功能的具体实现。
本质 模板模式的本质是利用C的虚函数特性使用接口将具体实现封装了起来实现了功能对外接口和功能具体实现的解耦。 访问者模式
示例https://www.runoob.com/design-pattern/visitor-pattern.html
使用场景
访问者模式用于将数据结构与数据操作相分离。
使用说明
访问者模式和迭代器模式类似。迭代器模式一般用来遍历数组所以没有把for封装起来。而访问者模式可以遍历一切类型的数据结构具体的遍历过程被封装在接收者内部。同时对每一个遍历得到的数组元素的操作被封装在访问者内部。每一种对元素不同的操作都需要新建一个访问者类。
接收者需要实现accept()接口访问者需要实现visit()接口。
本质 访问者模式的本质是封装了数据遍历过程同时也封装了数据操作过程以一种高度封装的方式实现了数据遍历操作功能。 结语
每种设计模式都有使用场景都有优点和缺点。随着需求的改变任何一种设计模式可能都将不再适用。