没别的, 就是把设计模式过一遍, 最后还补充了Boost库中用到的几个设计模式.
相关代码可以参考我的github库 设计模式C++实现
除了CTO之外, 技术领域的最高阶”架构师”的必修之术.
因为即使有机会, 我也不会去做”架构师”, 所以此篇是 最终篇
, 博客以后再不说设计模式.
(后续可能会有修订)
引子
设计模式, 面试的时候常考, 但是实际上工作中用到的, 也就那么几种: 工厂方法, 观察者, 代理, 装饰者, 单例等.
面向对象设计模式是一套被反复使用, 多数人知晓的代码设计经验总结. 一般分为: 创建型模式, 机构型模式, 行为模式.
正文
创建型模式
解决如何创建对象的问题, 详细内容可以参考: https://github.com/WizardMerlin/design_pattern_life/blob/master/创建模型.md
简单工厂
在工厂中集中相关的产品创建逻辑, 内部判断要创建那种具体的产品.
工厂方法(Factory Method)
在简单工厂的基础上, 改善扩展性, 定义接口用于创建对象, 但是具体的实现创建逻辑推迟到具体的子类中.
(每种具体的产品需要一个对应的具体工厂)
抽象工厂(Abstract Factory)
在工厂方法的基础上(创建还是交给子类去实现), 提供更多统一的创建接口, 可以一下生产一个产品族, 即每次一个子类工厂可以生成多个具体的产品.
建造者(Builder)
将复杂对象的构建(创建)与表示(组装)分离, 使得同样的构建过程可以创建不同的表示(不同的组合体).
先一个个的创建对象的每一个部件(builder里面不同的抽象方法来创建), 再统一组装成一个对象(从产品生成器中生成产品, 传入builder引用)
原型(Prototype)
原型模式使用类的实例通过拷贝的方式创建对象, 具体的拷贝行为可以定制.
最常见的用法为类实现一个 Clone()
成员函数(或者拷贝构造函数), 这个函数创建一个与原型相同或者相似的新对象
单例(Singleton)
运行时, 类有且仅有一个实例(避免产生多个实例对象), 但是注意线程同步问题.
结构型模式
如何组合类或者对象, 更而形成更大更有用的新对象; 减小耦合, 防止臃肿.
详细解释可以参考 : https://github.com/WizardMerlin/design_pattern_life/blob/master/结构型模型.md
适配器(Adapter)
把一个类的接口转换成另一个接口, 在不改变原有代码的基础上复用原代码; 或者使原来不同共同工作的相关类可以兼容工作.
(注意原有代码, 这一点是前提)
桥接(Bridge)
将抽象部分与实现部分分离(多个变化部分就使用多个抽象, 继承或者成员对象), 使它们都可以独立的变化.
(有多少处变化就进行多少处抽离)
组合(Composite)
将小对象组合成树形结构.(它们往往都有相似的结构, 例如文件和目录)
装饰(Decorator)
运行时动态地给对象增加功能.
外观(Facade)
为系统中大量对象提供一个一致的对外接口, 简化系统使用.
享元(Flyweight)
使用共享的方式节约内存的使用(如果对象已经存在了, 那么直接重用该对象).
代理(Proxy)
代理与被代理对象往往拥有相同的接口(可能继承同一个抽象类), client如果要调用相关动作, 就要通过代理接口, 而不能直接使用真实的动作类.
它的意图不是改变接口插入新系统(适配), 也不是为对象增加职责(装饰), 而是要控制对象.
智能指针库, 利用代理模式将原始指针包装,代理原始指针的职能.
行为模式
解决对象之间的相互调用, 动态行为等问题, 详细内容可以参考: https://github.com/WizardMerlin/design_pattern_life/blob/master/行为型.md
模板(Template method)
模板方法模式准备一个抽象类, 将部分逻辑以具体方法及具体构造子类的形式实现, 然后声明一些抽象方法来迫使子类实现剩余的逻辑.
不同的子类可以以不同的方式实现这些抽象方法, 从而对剩余的逻辑有不同的实现.
先构建一个顶级逻辑框架, 而将逻辑的细节留给具体的子类去实现.
命令(Command)
将一个请求封装为一个对象, 从而使你可用不同的对象对客户进行参数化.
(通常客户端的调用包括:方法+参数)
Command 模式通过被称为Command 的类封装了对目标对象的调用行为以及调用参数(命令消息模式)
职责链(Chain of Responsibility)
把对象连成一条链, 使链上的每个对象都有机会处理请求.
(当前处理者会保留一个引用指向下一个处理者)
一旦第一个责任处理者引发处理, 之后就开始不同的调用执行(直到停止).
策略(Strategy)
封装不同的“算法”, 使它们可以在运行时相互替换.
为所有算法定义一个抽象的算法接口并通过继承该抽象算法接口对所有的算法加以封装和实现具体的算法选择交由客户端决定(策略), Strategy 模式主要用来平滑地处理算法的切换.
通常能实现同一接口的算法, 功能类似, 如加密中的AES, DES.
中介者(Mediator)
包装了一系列对象相互作用的方式, 使得这些对象不必相互明显作用, 从而使它们可以松散偶合.(避免了直接交互)
当某些对象之间的作用发生改变时, 不会立即影响其他的一些对象之间的作用, 保证这些作用可以彼此独立的变化.
(但是中介类必须知道交互双方的信息, 即保留两者的引用)
观察者(Observer)–订阅发布
定义对象间一对多的联系, 当一个对象的状态发生变化时,所有与它有联系的观察者对象都会得到通知
备忘录(Memento)
备忘录对象是一个用来存储另外一个对象内部状态的快照的对象.
备忘录模式的用意是在不破坏封装的条件下, 将一个对象的状态捉住, 外部化, 存储起来; 从而可以在将来合适的时候把这个对象还原到存储起来的状态.
访问者(Visitor)
分离类的内部元素和访问它们的操作, 可以在不改变内部元素的情况下增加作用于它们的新操作.
(简单说, 原来类的成员方法, 全部封装到了一个单独的类Visitor中, 之后依靠accept(Visitor *)方法通过Vistor访问)
(因为访问还是在原来的类内部调用visitor对象, 所以可以给visitor传递this指针, 这样visitor就可以访问成员数据了)
状态(State)
允许对象在状态发生变化时, 行为也同时发生改变.(行为随着属性变化, 并且状态间可以内部流转)本质上是 判断然后调用相关犯法
逻辑的抽象.
(具体来说, 就是原来的类保留一个抽象State* state, 然后通过state对象进行调用; 由于state对象知道原来的类的内部状态, 所以可以做相关判断)
解释器(Interpreter)
给定一个语言, 定义它的文法的一种表示, 并定义一个解释器, 该解释器使用该表示来解释语言中的句子.
(同样的语句, 经过不同解释器的解释, 可能得到的结果就不一样了)
迭代器(Iterator)
提供一种方法顺序访问一个聚合对象中各个元素, 而又不需暴露该对象的内部表示.
(外部的iterator保留一个集合对象的引用, 然后内部记录索引, 进行对集合的访问)
(集合类只需要能够getIterator对象就可以了)
Boost库用到的
空对象
用于返回无意义的对象时,它可以承担处理null的责任
包装外观
通过外观的包装, 使应用程序只能看到外观对象,而不会看到具体的细节对象, 这样无疑会降低应用程序的复杂度, 并且提高了程序的可维护性.
不同于外观为大量对象或者说面向对象子系统提供一个统一的接口, 包装模式是为不同平台或者底层API提供一个统一的接口.
前摄器模式(Proactor)—分角色的模式
用于为异步事件多路分离和分派处理器的对象行为模式.
不使用线程就完成了异步操作(不考虑线程同步).
组成部分如下:
- 前设器: 1.创建完成处理器, 2.调用异步处理器, 3.调用异步多路分离器
- 完成处理器: 用于异步任务完成后的回调
- 异步操作处理器: 处理异步操作, 把完成的事件放入 完成队列
- 异步事件多路分离器:从完成队列中取出事件, 分配“完成处理器”(让它处理相关回调或者后续操作)
- 完成队列: 存放已经执行完毕的异步操作事件
asio就是使用该模式.