设计模式的个人总结
Contents
创建型模式
- 工厂方法
- 简单来说就是提供一个create方法
- 代码两个变化方向,一个是子类的扩展,一个是框架层的不变。
- 另外还有一种用法和单例有点像,提供一个create接口,但是返回的可能是公用的对象。
- 抽象工厂
- 单个类里有很好个create方法,用于创建不同的产品。
- 一般把创建操作独立成一个类A,然后组合进另一个类B。类B利用类A的接口完成具体的业务。
- 生成器
- 和抽象工厂有点像的,只是这里更强调步骤。生成器是把步骤隐藏,抽象工厂的步骤是不变的。
- 两个变化的方向,一个是创建不同的产品、一个是构建步骤不同,导致有两个继承树。
- 原型
- 就是一个clone接口,能够从已有的类copy一个新的出来。
- 比较适合的场景 怪物、AI的创建,怪物种类太多了,那么直接按照怪物的行为划分更下层的子类,通过组合的形式构造出来成千上万种怪物。
- 深入设计模式这种还要搞一个prototype继承树有点二,在游戏里组合用的更多些。
- 单例
- 全局访问点、通过封装保证只会创建出一个、延迟初始化
- 用的太多了,不过要写出一个线程安全的单例其实不容易。
- 隐式的构造时机,可能导致隐藏bug,不适合服务器场景,服务器要求行为固定
- 全局只能有一个对象,好处是调用可以少穿一个参数,坏处就是这个全局只有一个对象的限制很蛋痛,没法扩展成多个。
结构型模式
- 适配器
- 简单说就是套个壳,伪装成另外一种东西。非常朴素的一种设计模式,很常用。
- 装饰模式和适配器不太一样,装饰主要是想偷偷做一点其他事情。
- 桥接
- 功能和名字匹配,两种不同类型对象的中间连接的部分。
- 对象可以独立扩展,桥接部分也能独立扩展,这里面有三个变化的方向。
- 组合
- 同一类对象组合成一个大对象,偶尔用。
- 组合的模式可以有多种:并列、树等等。
- 使用范围有限,大部分类这样组合起来语义上就不通了。
- 装饰
- 简单来说就是穿一层衣服,增强功能。
- 外观
- 相当于一个大的模块,提供一个api类,把对外暴露的接口都放在这个类里。
- 使用者就不用关心模块内部的实现,最简单做法就是搞一个api.hpp暴露一些全局函数。
- 一个模块可以提供好几个外观。
- 享元
- 省内存,最常见的就是文字处理程序依靠该模式处理字符串。
- 游戏行业有很多特效、物件都可以用这个方法处理。
- 代理
- 非常常用的模式,比如数据库代理、RPC stub。
- 代理模式提供相同的接口,但是真实对象在另外的地方。
行为模式
- 责任链
- 常见于消息处理,一个消息过来,被一个链条下的handle消费。
- 有两种做法,一种是调用下一个节点由框架来做,一种是由节点来做。
- 节点来做比较适合插入时间统计的代码,这个节点相当于下一个节点的装饰器。然后也可以根据业务看是否取消继续调用,适合做拦截器。
- 形式可以不是链状,树也行,随意啥形状都行。
- 命令
- 游戏行业用的比较多的就是对同一个玩家输入的操作执行不同的响应。
- 本质上是框架复用。
- 迭代器:没啥好说的,框架复用,迭代模式任意扩展,stl用的太多了。
- 中介者
- 依赖导致,解除类之间互相调用产生的网状结构。
- 网状结构没了,都依赖中介者,这样只要改中介者,代码更容易改。
- 备忘录
- 用的很少的一个模式,就是把状态从对象中剥离,可以任意恢复状态。
- 观察者:
- 天天用的玩意,解耦,依赖倒置。
- 通知没有顺序,调用关系隐蔽,重入风险。
- 状态:和命令模式类似,是为了对同一个行为产生不同的反应,但是状态模式操作是一组的。
- 策略
- 代码分成两部分,上下文和策略,策略能独立扩展,上下文不变。
- 和命令模式有点像,不过目的不一样,命令不强调这个上下文。
- 模板方法:框架复用,和模板差不多,替换几个预设的步骤。
- 访问者:
- 双分发,不是很好用的一个模式,子类扩展还要改visitor。
- 框架复用,visitor就是一个遍历,然后每种类型对象调用不通的接口,接口的