2.1 适配器模式
把一个类的接口转化成客户希望的另外一种形式.
回调函数中需要用到的function<>绑定就是一种适配器. 原有的接口不支持, 通过适配器让其支持.
适配器有两种,
一种是类适配器, 用继承的方式实现, Adapter类继承了原来的类并实现了适配的方法.
另一种是对象适配器, 让类含有原来的类的指针/ 引用, 然后自己里面写一个方法内部转换一下接口.
2.2 桥接模式
将抽象部分与它的实现部分解耦,使得两者都能够独立变化。
例子: 对于颜色和笔头粗细, 这是不可分割的两种特性, 属于设计不当. 但是毛笔可以将水彩色和笔头粗细两种正交特性分开, 是良好的设计.
角色:
- 抽象类: 定义抽象接口, 抽象类中有一个实现类接口的指针
- 实现类接口:抽象定义另外一个维度
- 扩充抽象类: 定义抽象类实现的接口
- 具体实现类: 实现了"实现类接口"定义的接口
用户在持有一个抽象类的指针, 使用的时候实例化成一个扩充抽象类, 同时又可以实例化不同的具体实现类, 保证了两个方向的正交性.
桥接模式和适配器模式有什么不同? 在设计的时候使用桥接模式, 但是如果已经有了两个功能完善的类, 那么使用适配器模式.
桥接模式防止 构建抽象层和实现层过度耦合
缺点: 需要在设计的时候考虑到, 于是两者的关系建立在抽象层, 很难让以后的人识别出来
2.3 组合模式
组合多个对象形成树形结构以表示具有部分-整体关系的层次结构。组合模式让客户端可以统一对待单个对象和组合对象。
最理想的例子是树, 每次调用树的Add()方法来为他添加新的叶子节点.
组合模式有透明组合模式和安全组合模式, 透明组合模式要叶子节点也实现枝子节点的方法, 如Add和delete, 但是实现是没有意义的, 因此要做异常处理; 安全组合模式让枝子节点单独去继承组合模式, 然后自己去实现管理方法, 但是这种方法大大增加了实现的复杂性.
角色有:
- 抽象构件(定义了一些公共接口, 叶子构件和容器构件都要实现)
- 叶子构件
- 容器构件(里面可以有容器构件, 也可以是叶子构件)
优点: 清晰分层次地表达对象, 让客户忽略层次差异; 符合开闭原则;
缺点: 叶子构件/ 容器构件的行为受限, 因为他们来自于相同的抽象构件, 因此如果要使用特定的方法, 那么就要在运行的时候判断对象类型.
2.4 装饰模式
动态地给一个对象增加一些额外的职责。就扩展功能而言,装饰模式提供了一种比使用子类更加灵活的替代方案。
角色:
- 抽象构件:; 是具体构件和装饰类的共同基类, 定义了run()方法
- 具体构件: 继承自抽象构件
- 抽象装饰类: 继承自抽象构件
- 具体装饰类: 实现了抽象装饰类的方法
抽象装饰类中有一个抽象构件的指针, 于是具体装饰类的run()方法中先执行具体构件, 然后再执行装饰的方法.
同样的, 这个具体装饰类还可以被传入到其他的具体装饰类中.
优点: 装饰模式比继承更加的灵活, 可以动态扩展一个对象的功能, 并且可以多次装饰
缺点: 会增加很多小的对象, 更难排错. (装饰器一直持有的是基类的指针)
2.5 外观模式
隐藏了系统内部的类和细节, 封装了一个外观给用户去调用
注意事项:
- 不要增加额外的功能
- 不要返回内部子系统的组件给客户, 但是必要的时候提供native_handle方法给客户
- 外观模式的目的是提供一个高层次的接口, 所以不要进行低层次的单独业务执行
比如内部有一个用户类, 信用卡信息类, 余额类
要封装一个外观, 用户直接操作外观就可以创建一个新的储蓄账户
缺点: 增加减少子系统需要修改外观, 违反了开闭原则
2.6 享元模式
运用共享技术有效地支持大量细粒度对象的复用。
注意被共享的对象必须是细粒度的, 比如说单词池的二十六个字母, 围棋盘中的每一个围棋.
享元: 共享元数据.
享元分为外部状态和内部状态. 内部状态是不管外部怎么创建, 我的内部属性都是已知的(围棋的形状, 大小). 外部属性是根据不同的外部状况, 可能要实时改变(如围棋的位置, 黑白)
角色:
- 享元工厂: 创建享元, 同时还可以预先创造出享元池, 到时候直接给出
- 抽象享元
- 具体享元
缺点: 需要区分外部状态和内部状态.
2.7 代理模式
使用代理对象来实现对原对象的访问.
为什么不直接访问? 代理有以下几个好处
- 远程代理: 为远程对象提供了一个本地代理, 其他程序可以直接访问这个代理.
- 虚拟代理: 如果创建一个真实实际对象消耗过多资源, 先创建一个代理, 等空闲的时候让代理去创建真实对象.
- 保护代理: 不同对象的不同访问权限.
- 缓冲代理: 增加一层缓冲区, 来保存这些数据(不同用户共享)
- 智能引用代理: 如同shared_ptr
角色有:
- 抽象主题角色: 声明了代理和真实主题角色的共同接口, 客户端是针对抽象主体角色编程的.
- 代理主题角色: 在抽象主体的基础上, 还可以实现一些新的功能, 同时保存了一个真实主题角色的指针(其实保存一个抽象主体角色的指针也行).
- 真实主题角色: 实现了抽象主题角色的接口
LOG功能就是一个代理模式. 先打印出来调用时间, 然后再真实的调用实际的函数
优点: 增加新功能时没有动抽象主题角色, 降低系统耦合度, 符合开闭原则
缺点: 让系统变慢
网友评论