GOF设计模式摘要汇总

参考资料:图说设计模式
参考资料:java-design-patterns

关于GOF设计模式,参考资料繁多。此文档不关注模式的实现细节,仅做对比总结。

为了保持完整性:

  • 诸如,组合、桥接、单例这些简单的模式也收录并做了简单的描述。
  • 同理,对于FP编程大火的今天,诸如:访问者,命令这样的模式其实已经没有多大意义,还是本着完整的原则做了整理。
  • 实在不能理解,备忘录、解释器也能被归类到设计模式,分组到莫名其妙。

删除了性能优化型的模式,[享元模式]。这根本就是优化好吧,设计理论中有性能优化么?

基本原则

  • 单一职责原则(Single Responsibility Principle, SRP)
  • 开闭原则(Open-Closed Principle, OCP)
    • 对扩展开放,对修改关闭
    • 抽象化是开闭原则的关键
  • 里氏代换原则(Liskov Substitution Principle, LSP)
    • 所有引用基类(父类)的地方必须能透明地使用其子类的对象
    • 子类不要改变父类的行为
    • 尽量避免Override
  • 依赖倒转原则(Dependency Inversion Principle, DIP)
    • 抽象不应该依赖于细节,细节应当依赖于抽象。换言之,要针对接口编程,而不是针对实现编程
  • 接口隔离原则(Interface Segregation Principle, ISP)
    • 使用多个专门的接口,而不使用单一的总接口,即客户端不应该依赖那些它不需要的接口
    • 即每个接口承担相对独立的角色,接口尽量小而专
  • 迪米特法则(Law of Demeter, LoD)
    • 一个软件实体应当尽可能少地与其他实体发生相互作用
    • 少互动,低耦合,少麻烦。

结构型模式

1对1结构型

Adapter适配器:

  • 1 in 1 结构
  • A 持有B的抽象,C跟B没有直接关系,D实现B包含C,即D对C做了关于A的适配。
  • 适配并重用已有的方法,适配第三方库降低耦合。
  • 简单易懂,使用频繁

Decorator 装饰

  • 1 in 1 结构
  • 在原有对象上的包装或者增强
  • 又是组合优于继承的好例子
  • 一般而言,继承只用于设计抽象结构,很少会继承实类型做扩展。增强实类型,装饰是个好选择。

Proxy 代理

  • 1 in 1 结构
  • 动态代理的应用太多了,不解释了。

关于 代理,装饰,适配器三种 1in1结构模式的对比:

与原对象相关性 侧重点 目的
代理模式 极强,对外方法一致。 间接引用 访问控制、延迟加载、面向切面编程
装饰模式 强。类似继承的关联。 功能增强 非继承实现功能增强,灵活适配。
适配器模式 弱。只要满足适配规则即可。 兼容解耦 兼容老代码,兼容三方库。依赖适配接口而非实现。

多合一结构型

Composite 组合

  • n combine 1 结构
  • 多个对象组合成一个对象来用
  • 简单易懂

Facade 外观

  • n combine 1 结构

  • 这玩意不就是对外暴露的api接口么

    • 一图见真相



Bridge桥接

  • 1 associate n 结构
  • 以插件的方式添加功能特性或扩展属性。
  • 面向接口而非面向实现;组合优于继承
  • 避免类型爆炸的常用手段

关于 组合,外观,桥接三种 多合一结构模式的对比:

侧重点 目的
组合模式 简单组合 实在没啥可说的了
外观模式 多子合一 对外统一接口
桥接模式 即插即用 依赖于抽象

构建型模式

1对多构建型

Simple Factory简单工厂

  • 1 build n 型
  • 基本的对象构建模式,构建逻辑都耦合在工厂类中
  • 扩展产品需要修改工厂逻辑
  • 只有工厂的产品做了抽象,工厂类自己是实类型

Factory Method工厂方法

  • n build n 型
  • 对工厂的产品以及生产产品的方法都做了抽象
  • 通过实类型的工厂子类来决定具体的产品类型
  • 在抽象的过程中,工厂的概念被淡化,仅做为一种抽象的约束
  • 扩展性良好,无论是产品还是工厂都可以很好的扩展。

Abstract Factory抽象工厂

  • 1 build n build n*m 型
  • 结合了简单工厂和工厂方法从另一个角度做了更深层次的抽象。
  • 工厂的选择,决定了产品族。选择工厂时类似简单工厂。
  • 产品族内部的产品生产则是实现了抽象,类似工厂方法的实现。
  • 具体情况请参看参考资料。

1对1构建型

Builder构建器

  • 1 build 1 型

  • 当一个对象过于复杂时,创建一个对象就变得麻烦起来。大量的重载构造器,setter,甚至还可能有init方法,使得使用者想要得到自己想要的对象还需要了解具体的实现。这个时候最好的解决办法就是,让专业的人做专业的事。

  • Builder可以在最终builder的时候做校验,对构建过程中的错误给出友好的提示。

  • 对构建参数的校验独立出来,单一职责,代码更漂亮。

  • lombok天天用。


Prototype原型

  • 1build1 型
  • 创建对象最快捷的方法:有一个创建好的对象供复制。
  • 想想我们做model的转换,BeanUtil copy,然后稍微改改属性。
  • 作为原型的对象应该拥有,最抽象、最纯粹、最稳定不易变的属性。若使用原型创建对象之后还要大量覆盖之前的属性,

Singleton单例

  • 1 build 1型
  • 只有一个实例。
  • 面试问的最多的设计模式。该模式概念及其简单,以至于问题的侧重点跑偏的如何保证实例的唯一性。
  • final类,private构造器,privite static instance,public getter 最简单的解决方案。
  • 其实一个全静态的类是不是也是单例呢?

行为型模式

1对1交互行为

Command命令

  • 1notify 1
  • 别名:动作(Action)模式,或事务(Transaction)模式
  • 对消息指令做了抽象封装。消息指令本身包含了接受者,调用者本身不用关心接受者。
  • 重点在于命令的undo,redo,命令组。也是为啥有事务别名的原因。

1对多交互行为

Observer 观察者

  • 1 notify n
  • 别名很多:发布-订阅(Publish/Subscribe)、模型-视图(Model/View)、源-监听器(Source/Listener)或从属者(Dependents)
  • 适用于消息事件通知的模型,广泛用于各大框架,中间件,想不了解都难。
  • 解耦神器,居家必备

Chain of responsibility责任链

  • 1notify n
  • 通过给多个对象处理请求的机会,避免请求的发送方与接收方耦合。将接收对象链起来,并沿着链传递请求。
  • 链条上的每一个接收方自己决定是否处理请求,是否继续将链条传递下去。
  • 责任链对比于观察者的不同点:处理逻辑与接收者顺序相关;可以截断消息;关心处理结果。

关于 观察者,责任链,命令三种 通知型模式的对比:

模式 通知方式 是否有反馈 侧重点
观察者 广播,每一个订阅者都通知 解耦,1对n广播式通知
责任链 链式传播,可能会中途返回 有返回信息 层级式链条传播,寻找责任人,接收反馈
命令 一对一精准 动作的undo,redo,整体命令序列的控制

多对多交互行为

Mediator 中介者

  • n notify n
  • 多个同事对象的交互通通过中介方中转,而非直接交互。
  • 同时对象关联中介的方式类似于注册。同事对象与中介者互相引用。
  • 网状结构转化为星型结构,降低结构复杂度。
  • 同事之间通过中介使用代号进行精准交互,或者不使用代号进行群组动作。

抽象

Strategy 策略

  • 策略模式不关注行为动作的目标,而是关心行为本身的封装
  • 简单来说就是对行为统一封装,上层依赖抽象
  • 代码上很像很像桥接,只不过逻辑侧重点不相同
  • 策略的装配仍然需要硬编码,与其定义一堆策略实体,直接使用Lambda传递策略函数或许是更好的选择。

Template-Method模板方法

  • 做继承抽象时经常使用的设计模式,十分常用,十分有效,重点理解。
  • 共性方法抽象到父类,具体实现留给子类扩展,以便最大程度的复用代码,更能精简逻辑。
  • 不多说了,各大框架都有例子。

Iterator 迭代器

  • 提供按顺序访问聚合对象的元素而不公开其底层表示的方法。
  • Collection的迭代器基于此模式设计,烂熟于心了。
  • 同上,不解释了。

State 状态

  • 对状态做封装,即状态改变的伴生行为与不同状态下的行为被封装在状态类中。
  • 我们经常用枚举或者直接用字符串做状态,实际上对状态的处理都放到状态拥有者中去做。这样对于 单据状态审批状态这种通用性状态就会出现很多重复的代码逻辑。对于这种情况就可以使用状态模式做封装。

Visitor 访问者

  • 动态的扩展对象的行为而不用修改对象本身。
  • 通过在对象中定义通用的accept方法接受抽象的visitor来实现方法的动态扩展。同样的accept方法调用传入不同的visitor会有不同的行为。
  • vistitor中会持有对象的实引用,使用不慎会产生循环调用。
  • 随着fp编程的普及,访问者模式估计也会逐渐消失吧。

莫名其妙

Memento备忘录

  • 存储状态以便恢复。。。
  • 这玩意也能单独拿出来叫做设计模式么?
  • 最保险的备忘方法还是持久化吧,这东西现在还能拿来干嘛。

Interpreter 解释器

  • DSL的解析
  • 正则表达式,各种format,语法解释器。
  • 这东西也放到设计模式里么。。。。

结语

断断续续的整理完稿,回过头来看关于GOF23其实还是蛮简单的。

​ 简单的模式,只要你有oo思想就能设计出来,不必学习也知道。

​ 经久不衰的模式各大框架现在还在用,在实践中学习深化;

​ 被编程模型淘汰的模式看看就好,不必深究;

​ 莫名其妙的糟粕不理会就好,谁知道是什么历史原因遗留下来的。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343