设计模式概念:
设计模式描述:
设计模式扮演的角色:
应用程序
工具箱
使用设计模式进行代码重用
例如:C++ STL中的容器、迭代器和算法。
框架
强调设计重用
在框架中使用模式使学习框架的使用更加容易
优缺点:
使用设计模式的缺点
使设计复杂化
根据空间和时间要求,降低系统性能。
仅在需要时使用设计模式:
灵活性
可扩展性
便携性
所见即所得文档编辑器
设计问题
文件结构
格式化
修饰用户界面
多种外观和感觉标准
用户操作
拼写检查和断字
特点
类图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Yqyly0Vp-1587370424295)(C:\Users\hasee\AppData\Roaming\Typora\typora-user-images\1560655234244.png)]
代码
class Glyph {
public:
virtual void Draw( Window * )=0;
virtual void Bounds( Rect & )=0;
virtual bool Intersects( const Point &)=0;
virtual void Insert(Glyph *, int)=0;
virtual void Remove(Glyph *)=0;
virtual Glyph * Child (int)=0;
virtual Glyph * Parent( )=0;
}
composite pattern
概念
类图[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZrBG84PC-1587370424297)(C:\Users\hasee\AppData\Roaming\Typora\typora-user-images\1560655539863.png)]
结果
合作:
后果:
缺点:
composition 和 compositor
组成 composition
初始的,它包含未格式化的对象(字符、数字等)。格式化算法将结构对象(行、列等)插入其中。
合成器 compositor
不同的格式化算法被封装到类中
接口
void setcomposition(成分*)
虚拟虚空合成()
Composition可以理解为作品,compositor可以理解为作者
类图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RgmEJChk-1587370424300)(C:\Users\hasee\AppData\Roaming\Typora\typora-user-images\1560655984320.png)]
意图
意图:
将对象组合成树形结构以表示“部分-整体”的层次结构。composite使得用户对单个对象和组合对象的使用具有一致性
效果:
很容易添加新的组件
Strategy pattern
意图:定义一系列算法,并将其封装起来,并且使他们可相互替换
适用性
结构
类图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-P8xzop7b-1587370424303)(C:\Users\hasee\AppData\Roaming\Typora\typora-user-images\1560656235746.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-U96KPm4H-1587370424307)(C:\Users\hasee\AppData\Roaming\Typora\typora-user-images\1560656245934.png)]
代码
void Composition::Compose() {
switch ( _breakingStrategy ) {
case SimpleStrategy:
ComposeWithSimpleStrategy();
break;
case TexStrategy:
ComposeWithTexStrategy();
break;
// ...
}
}
// With strategy pattern
void Composition::Compose() {
_compositor->Compose();
// ...
}
Decorator pattern
意图:动态地将额外的责任附加到对象上。为扩展功能提供了一种灵活的子类替代方案。
它是一些单独的对象(不是整个类),功能可以扩展到这些对象。例如,边框、滚动条。
基本类由decorator类包围
decorator类符合基本类的接口。
接口的实现:
将请求转发到基本类
在转发之前或之后执行任何其他操作
结果:修饰符可以递归嵌套。
类图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8L9aujJG-1587370424310)(C:\Users\hasee\AppData\Roaming\Typora\typora-user-images\1560663343784.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RnxExjNQ-1587370424312)(C:\Users\hasee\AppData\Roaming\Typora\typora-user-images\1560663382557.png)]
适用性:
在运行时添加或删除职责
组件类不需要知道任何关于它的修饰符的信息。
装饰模式与复合模式的比较
装饰模式是退化的复合模式
意图不同
装饰:用于添加其他功能
复合:用于对象聚合
保持组件类的轻量否则,装饰器将太重而无法使用
example
不用装饰模式缺点:流的所有对象都具有属性“bcompress”、“bto7bits”和
特定于数据压缩和数据转换的操作,即使您想要的是一个纯粹的memoryStream对象,它不具有附加功能和属性。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aCXYeMgA-1587370424314)(C:\Users\hasee\AppData\Roaming\Typora\typora-user-images\1560663568298.png)]
Stream * fStream = new FileStream("test.cpp");
Stream * mStream = new MemoryStream();
Stream * fcStream = new CompressingStream(
new FileStream("test.cpp") );
Stream * f7Stream = new ASCII7Stream ( new FileStream("test.cpp") );
Stream * fc7Stream = new CompressingStream(
new ASCII7Stream ( new FileStream("test.cpp") ));
fc7Stream->PutInt(12);
fc7Stream->PutString("hello");
Command Pattern
意图:
意图:将一个请求封装成为一个对象,从而你可用不同的请求对客户进行参数化
理解:command类将要发送的请求作为一个实例变量,可以进行转发,请求里有执行该请求的全部信息
需求:
可以将多个小部件映射到同一操作上
我们不希望实现操作的类和接口类之间的紧密耦合。
我们希望支持撤消/重做功能
还必须存储撤消信息
例如,更改所选文本的字体文本范围文本的原始字体
例如,删除所选对象应存储所有对象的信息!
不可撤销性
无意义的命令不应撤消
命令是否无意义应该在运行时确定
添加命令::可逆
适用性
支持撤消
支持上下文相关菜单
支持命令宏
支持记录更改以恢复崩溃的系统
支持信息系统中的事务概念
类图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yHuyUTHb-1587370424316)(C:\Users\hasee\AppData\Roaming\Typora\typora-user-images\1560664020523.png)]
Abstract Factory Pattern
意图:
意图: 通过创建一系列相关或者相互依赖对象的接口,而无需指定他们的具体类。
实现: 通过父类接口调用子类,这样用户只需要接触到父类(抽象类),而非接触到子类(具体类),方便客户调用
子类还可以将同一风格的组件封装便于同一调用,便于不同风格的切换
问题:
冗长:每次我们创建一些小部件时,都必须使用switch语句
可能会导致问题:您创建了一个Mac样式的按钮,但当前样式是Motif。
很难切换样式:如何跟踪旧的小部件来销毁它们?
类图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SeQGfwnK-1587370424319)(C:\Users\hasee\AppData\Roaming\Typora\typora-user-images\1560664358694.png)]
代码
switch (Style) {
case Motif:
guiFactory = new MotifFactory( ); break;
case Mac:
guiFactory = new MacFactory( ); break;
case PM:
guiFactory = new PMFactory( ); break;
}
ScrollBar * sb = guiFactory->CreateScrollBar( );
Button * bn = guiFactory->CreateButton( );
Menu * mn = guiFactory->CreateMenu( );
实现
工厂:单件
定义可扩展工厂
假设我们要将一个小部件“列表框”附加到上一个工厂
解决方案1:更改工厂类的接口。
解决方案2:定义一个“制造”操作来生产所有产品。
可扩展
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PuX8gPUz-1587370424321)(C:\Users\hasee\AppData\Roaming\Typora\typora-user-images\1560664476139.png)]
Widget * MotifFactory::Make(string name)
{
if ( name == "ScrollBar" ) return new MotifScrollBar();
// other widgets ...
// to append a new widget
if ( name == "ListBox" ) return new MotifListBox();
}
//...
ScrollBar * sb = dynamic_cast (guiFactory->Make("ScrollBar") );
ListBox * lb = dynamic_cast (guiFactory->Make(“ListBox”);
Iterator & visitor pattern
意图:
通过迭代访问信息
容器和迭代器都有其基类
类图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TZdJ6c18-1587370424323)(C:\Users\hasee\AppData\Roaming\Typora\typora-user-images\1560667089330.png)]
Proxy pattern
意图:为其他对象提供这一种代理以控制对这个对象的访问
理解:应该是有两个原因,第一个便于操作,就像书上的例子,第二个是为了安全,PPT上的例子
书上例子:使用图像proxy替代真正的图像,并在需要的时候负责实例化这个图像操作
为了自动删除迭代器,我们使用代理(proxy)模式(将有关object的操作封装成为一个类便于集成调用)
将每个指针封装到一个对象中
在对象中,重载->和*运算符
将对象声明为堆栈变量
当对象超出范围时,其析构函数将删除指针
Iterator Pattern
意图:提供一种顺序访问一个聚合对象中的各个元素,而不暴露该对象的内部表示
一般的方法:迭代器
Robust iterator
解决的问题:
添加或删除元素,迭代器依旧指向列表中按索引对应的元素
在添加或删除元素后,列表可能会被重新分配内存,迭代器依旧能指向对应的元素
PreorderIterator
按事先决定的顺序,去遍历一颗有层次的树
PPT上遍历的顺序规则
按照中左右深度遍历的顺序进行遍历,在完成左右节点的遍历后,Isdone,栈中删除左右节点
类图[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nCeEugax-1587370424325)(C:\Users\hasee\AppData\Roaming\Typora\typora-user-images\1560667808321.png)]
当创建迭代器时,用聚合来注册它。在插入和删除时,聚合调整迭代器的内部状态
类图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZIunD798-1587370424327)(C:\Users\hasee\AppData\Roaming\Typora\typora-user-images\1560668151756.png)]
visitor pattern
意图
意图:表示作用于某对象中的各元素操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
不同的object适用的analyzer不一样,为了更安全,将分析与迭代分离开来,同时应用多态将其简单化。
类图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hfaJL2iq-1587370424328)(C:\Users\hasee\AppData\Roaming\Typora\typora-user-images\1560668675437.png)]
Builder pattern
意图:
意图:
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示
在RTF文本编辑器中,转换器类称为生成器,而阅读器称为导向器(director)
ConcreteBuilder其中一项功能为:定义并明确它所创建的表示
效果:
生成器隐藏了产品的内部结构和装配细节,使得代码模块化以及提高了其可复用性
问题是:将RTF文档转换为纯文本、tex和textwidget格式。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WI1Fjazs-1587370424330)(C:\Users\hasee\AppData\Roaming\Typora\typora-user-images\1560668763567.png)]
特点
将转换器与读卡器分离
隐藏创建和组装复杂对象的详细信息
重新使用解析算法
类图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hduyqvhi-1587370424332)(C:\Users\hasee\AppData\Roaming\Typora\typora-user-images\1560668811472.png)]
参与者
生成器
指定抽象接口
具体的生成器
通过与其他对象交互来构造和组装部件
对象
检索产品
导向器
调用生成器构造产品
时序图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A4v7Vwvt-1587370424334)(C:\Users\hasee\AppData\Roaming\Typora\typora-user-images\1560669039263.png)]
结果
构建器隐藏了产品的内部结构和组装细节模块化和代码重用
实现
生成器接口必须是常规的
有时我们可能需要访问之前构建的产品的部分。
课程问题
有关生成器模式和抽象工厂模式的区别
生成器
生成器可能通过调用其他类来组装产品
生成器是逐步组装产品的
抽象工厂
抽象工厂的客户负责组装产品
抽象工厂一次把产品组装完
框架
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VJQWr2Gp-1587370424335)(C:\Users\hasee\AppData\Roaming\Typora\typora-user-images\1560669280418.png)]
意图:
定义一个用于创建对象的接口,让子类决定实例化哪一个类。factory method使一个类的实例化延迟到子类
效果:连接平行类的层次
意图:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象
问题
基于现有原型对象创建新对象的创造模式。
适用性
从头开始建造一个物体是很昂贵的。
需要一个现有对象的副本。
音乐乐谱编辑
自定义常规框架
有用于添加新图形对象的工具
有操作图形对象的工具
类图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MSBWtdSX-1587370424337)(C:\Users\hasee\AppData\Roaming\Typora\typora-user-images\1560669439516.png)]
实现
使用原型管理器
注册、浏览和取消注册原型
实现克隆操作
浅复制指针指向同一内存块
深度复制
意图:
将一个类的接口转换成为客户希望的另一种接口。Adapter模式使得原先由于接口不兼容而不能一起工作的类可以一起工作。
效果
适配器应当添加适配器者所没有但必需的功能
适配器的工作量取决于目标接口跟适配者的相似程度
可插入的适配器:能够适应不同接口的适配
类图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-udsdzKG4-1587370424338)(C:\Users\hasee\AppData\Roaming\Typora\typora-user-images\1560669606088.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wKLIaScc-1587370424340)(C:\Users\hasee\AppData\Roaming\Typora\typora-user-images\1560669590073.png)]
结果
适配器应附加适配器没有的任何必要功能。
两种方案的区别
多重继承:
类组合:单个适配器与许多适配器一起工作:适配器本身及其所有子类
适配器的工作量取决于Targe接口与适配器的相似程度。
实现
可插拔适配器
能够适应不同接口的适配器。
lambda表达式本质上是一个匿名函子
语法
[capture(parameters) -> return_type { function_body }
capture部分表示将要以何种方式访问哪些外部对象。常见形式:
[] // 不访问任何外部对象
[&] // 函数体中对外部对象的访问默认为引用方式
[=] // 函数体中对外部对象的访问默认为值传递方式
[x, &y] // 以值传递的方式访问外部x,以引用方式访问外部y
[&, x] // 以值传递的方式访问外部x,以引用方式访问其它外部对象
[=, &z] // 默认为值传递方式,但以引用方式访问z
[this] // 甚至可以访问类的私有数据成员
可以捕获外部的局部对象。
如果参数为空,“()”也可以省略。不过不建议这么做。
如果函数体中所有return语句的返回类型是一致的,return_type部分可以省略。
closure。闭包。指运行阶段一个lambda表达式对应的一个对象
意图:将抽象部分同实现部分分离,使他们可以独立地变化
问题
有两个因素:窗口类型和窗口实现
我们使用两个独立的类层次结构
一个模型不同类型的窗口
另一个要对windows的详细实现建模,我们需要为所有可能的操作找到一个“窄”的接口。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BhgjyoLf-1587370424342)(C:\Users\hasee\AppData\Roaming\Typora\typora-user-images\1560669854178.png)]
类图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EDThxkft-1587370424344)(C:\Users\hasee\AppData\Roaming\Typora\typora-user-images\1560669835788.png)]
讨论
抽象层次结构和实现层次结构都可以通过子类化来扩展。
实现中的更改不会影响摘要(不需要重新编译)
桥接和策略模式之间的差异
策略模式:对于一个操作,运行时开关具有上下文行为模式
桥接模式:类层次结构
意图:为子系统中的一组接口提供一个一致的界面,facade模式定义了一个高层接口。
动机:大多数用户并不关心子系统如何实现,只关心能否子系统是否有一些简单的接口,同时又有一些用户想要直接接触子系统的全部组件
理解:将子系统封装并提供一些简单的接口供大部分用户使用
解释图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OnSZ05EE-1587370424346)(C:\Users\hasee\AppData\Roaming\Typora\typora-user-images\1560670293955.png)]
例子类图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4BZNve5A-1587370424348)(C:\Users\hasee\AppData\Roaming\Typora\typora-user-images\1560670312778.png)]
意图:
使多个对象都有机会处理请求,从而避免请求的发送者和接受者的耦合关系。将这些对象连成一条链,并沿这
条链传递请求,直到有一个对象处理它为止
处理顺序:
special help-general help-even general help
提交请求的对象并不明确知道哪个一对象将会处理它,那么我们说这个请求有一个隐式接收者(implicit receiver)
职责链上的对象都有一致的处理请求和后继者的接口
效果:
松耦合
发送者只知道自己的请求会被适当地处理
职责链的顺序可以被动态地改变
类图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0xXm89QW-1587370424351)(C:\Users\hasee\AppData\Roaming\Typora\typora-user-images\1560670389986.png)]
结果
松耦合
发送方只是简单地知道它的请求将得到适当的处理。
对象的责任可以动态更改
实现
链的实现
定义新链接
使用现有的
复合模式中的父指针。
请求的表示
只是一种请求
请求代码(整数或字符串)
参数必须打包和解包
请求对象
意图:给定一个语言,定义它的文法的一种表示形式,并定义一个解释器,这个解释器使用该表示来解释语言中的句子
理解:使用类来表示语言的文法
先使用文法定义语言,然后用文法来表示句子,最后解释句子
常常会使用composite pattern
类图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ag6rq6MN-1587370424354)(C:\Users\hasee\AppData\Roaming\Typora\typora-user-images\1560670616588.png)]
实现
应用访问者模式定义解释操作
依赖性分析
示例:如果循环内的表达式不依赖于循环的局部变量,则只能计算一次。
通常采用保守近似法。
过高估计读取集
效果缓存
平行度
懒惰的评估:在明确要求之前不计算任何东西。
意图:
定义对象间的一种一对多的关系的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新
这一模式中的关键对象是目标(subject)和观察者(observe)。一个目标可以有任意数量的依赖它的观察者,一个观察者也可以观察多个目标。一旦目标的状态发生改变,所有的观察者得到通知。作为对这个通知的响应,每个观察者都将查询目标以使其状态与目标状态一致
效果:
观察者与目标之间有虚拟的连轴
支持广播交流
类图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FejKBeuN-1587370424356)(C:\Users\hasee\AppData\Roaming\Typora\typora-user-images\1560670817055.png)]
结果
主体与观察者的抽象耦合
主题和观察者可以属于软件系统的不同层。
支持广播通信
观察者可以忽略更新消息
实现
观察者可以观察到多个目标
eg[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kBdCtfD0-1587370424358)(C:\Users\hasee\AppData\Roaming\Typora\typora-user-images\1560670919348.png)]
在这种情况下,当一个主题向观察者B发送更新消息时,后者必须知道谁发送了消息。
谁触发更新
主题对象立即触发更新消息。
客户机在一系列状态更改有效后触发更新消息
发生了什么变化
推送模型
所有信息都包含在update方法的参数中
拉取模型
仅为感兴趣的特定事件注册观察者
无效主题::附加(观察者*、方面和兴趣)
意图:保证一个类仅有一个实例,并提供一个访问他的全局访问点
实现:让类自身负责保存它的唯一实例。这个类可以保证没有其他实例被创建(通过截取创建新对象的请求),并且它可以提供一个访问该实例的方法。通过定义一个static classname *instance,判断instance是否为空来判断当前类是否存在实例