首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >【笔记】《HeadFirst设计模式》(1) —— 从策略模式到外观模式

【笔记】《HeadFirst设计模式》(1) —— 从策略模式到外观模式

作者头像
ZifengHuang
发布2020-07-29 16:15:34
发布2020-07-29 16:15:34
8790
举报
文章被收录于专栏:未竟东方白未竟东方白

这本书简洁易懂地介绍了十多个设计模式,但是由于这是有很多图片的结构比较杂乱的书,理出一套系统的笔记并不容易,所以这里就只是把提到的设计模式大概总结了一下。这本书虽然长达六百余页,但引导用的内容占了绝大多数,干货比较分散,因此写出来的内容不会很多。这篇将包括1-7章的内容,下一篇包含8-14章的内容完结掉。

0 设计模式简介

  • 设计模式是从OO系统中被总结出来的一套编程理论,本质是为了优化代码的复用,让老代码尽可能地留存,让新代码自然地进入项目
  • 设计模式是与其他程序员共享的词汇,让我们与他人交流架构设计时变得容易
  • 设计模式并非代码或库而是一种思维方式,让我们把思考的层次提高到模式层面而非停留于琐碎的实现上
  • 设计模式能让初级开发人员有一个系统的架构目标来学习从而快速提高
  • 不要犯上“模式病”让自己无论什么问题都陷入模式的思考
  • 我们可以随时利用设计模式来优化我们的代码,也可以用来重做我们的旧代码
  • 设计模式的核心是得到一套弹性,方便维护,可变化的系统
  • 当无法找到合适的设计模式时,采用一些通用的面向对象原则很有效,关键在于要想到之后需要面对的变化

1 策略模式

  • 策略模式首先是一个定义一系列的策略接口(算法簇)的大基类,然后子基类选择需要的接口来继承,用户自定义的类再选择所真正需要的具体策略实例化在接口上
  • 这样可以通过基类抽象地调用一系列的用户类的抽象接口方法,用户又可以自由地选择自己类具体行为的内容,也让算法可以互相替换
  • 用组合来代替继承
  • 多用组合少用继承提高可维护性和可扩展性
  • 所以我们要找到应用中可能会变化的东西,将它们独立出来,不会变化的部分则可以复用
  • 应该针对接口编程而不是针对实现编程

2 观察者模式

  • 观察者模式的关键是定义观察者和可观察者,观察者需要先在可观察者处注册(例如用一个数组保存),然后可观察者可以以此推送信息给观察者,整体来说类似报纸与订阅户的关系
  • 观察者都实现了相同的接口,可观察者也有一样的接口,当可观察者需要通知观察者时直接把所给的内容用这个接口批量push过去,不用互相了解内在的具体实现
  • 观察者也可保存对可观察者的引用,需要的时候pull所需的数据(但这样效率低下且复杂,不被推荐)
  • 观察者模式下双方平时都保持自己的运作,只有当监听到push或pull时才响应,效率高,在现实中非常常见
  • 保证了两个对象间的松耦合,让彼此交互而不用知悉细节。让我们可以很轻松地加减观察者,改变一方不影响另一方

3 装饰者模式

  • 装饰者模式的好处是我们可以不断地嵌套着给被装饰者增添功能
  • 装饰者和被装饰者都继承自同一个基类,之所以分开描述是因为装饰者模式的特点是可以层层嵌套,具体的实现方法是装饰者都带有一个类型是基类的变量
  • 装饰者可以扩展被装饰者的功能(通过对函数重写中调用被装饰者的相同函数),或者增加新的的功能
  • 每个组件都可以单独使用或者被装饰后再使用
  • 装饰者模式的缺点是可能产生很复杂的嵌套。回忆下Java的IO类是不是常常需要复杂的构造参数?那就是典型的装饰者模式
  • 装饰者模式常常包含很多很多的组件类,用工厂模式能很大程度改善这个问题

4 工厂方法模式&抽象工厂模式

  • 工厂的目的是甩锅,因为客户代码目的仅仅是使用对象,并不想考虑如何得到这个对象,也就是让客户代码尽可能离new运算符远一些
  • 简单工厂直接包装了这个new,意义在于当对象创建发生改变时可以直接在一个地方修改此初始化过程
  • 工厂方法模式抽象了这个类,它抽象了一个产品,然后由具体产品工厂来生产这些类,其中具体生成对象的代码由子类具体工厂来实现。客户通过调用抽象的产品工厂来生成产品,但是不用在意具体是那个工厂在运作
  • 工厂方法的描述常常是“让子类决定生成的产品”,这个意思是指编写抽象工厂时我们不知道具体会生成什么产品,具体生成的产品是由下面继承的工厂类决定的,这个过程是编译时决定的
  • 抽象工厂方法从产品中抽象出组件家族,得到一个抽象的复杂工厂。客户可以直接使用抽象工厂的接口得到一系列组件然后用抽象的组件实现产品。组件的具体实现由继承的子类工厂实现,这样客户可以利用产品的共性来操作而不用接触工厂产生的具体产品,进一步地抽象化
  • 因此抽象工厂的每个方法都由工厂方法实现,是对工厂方法的包装。工厂方法进行实现,抽象工厂创建产品的抽象,整合和简化这部分的用户代码

5 单件模式

  • 也称为单例模式
  • 通常来说访问单件的共有函数叫getInstance
  • 由于单件实例是静态的(保证唯一性),所以getInstance常常也是静态函数
  • 就是把构造函数写成私有然后用有限制的公有函数来包装实例化过程
  • 当需要控制实例个数的时候也可以用这个模式,在类内用计数器来约束即可
  • 好处是比直接让类对象为静态变量好处理,防止了一些初始化次序的bug,允许了延迟实例化,还方便管理。全局变量法不能保证只有一个实例且全局变量容易造成命名空间污染
  • 如果有不同的命名空间,则要小心需要保证单件在一个空间里
  • 单件的实例化部分可能要注意多线程同步问题,可以通过加入同步锁或放弃延迟实例化或加入双层锁(外层判断是否存在对象,内层初始化部分用同步锁,这是利用了单件只初始化一次的特性)
  • 单件类不方便被继承,因为继承会导致派生类都共享同一个单件,这感觉很奇怪,因此单件不适合写到库中来使用

6 命令模式

  • 命令模式的核心是让具体的执行与调用者解耦,调用者负责与用户交换,然后调用当前调用者的命令变量。命令是一个单独的对象,内部连接着目标对象并有一系列细节操作,负责与目标交互,对外只暴露一个execute函数给调用者使用。因此对象并不知道具体操作到底如何,只要按照设置execute即可
  • 命令可不局限于单个命令,可以用数组实现宏命令
  • 空命令是一个很好的编程思想,即当调用者没有指定变量时,传入一个不进行操作的命令,防止了检查是否为空的繁琐操作
  • 让每个命令都写一个undo操作,然后在调用者处储存一个栈,用栈配合可以完成常见的连续撤销操作。这个栈持久化下来可以完成日志保存,方便恢复状态
  • 也可以用新建一个命令队列来完成流水式处理
  • 命令可以由目标对象工厂化提供

7 适配器模式&外观模式

  • 适配器模式的对象适配器利用一个新的类实现当前所需的接口,然后包装旧的类来完成适配,避免对旧代码的更改下支持新的代码
  • 实现适配器需要的工作与接口大小成正比,但是适配器将端的变化封装在里面,更易用有效。客户不用为了新的接口而改变自己,减少了新旧代码混用时可能发生的问题(要记得设计模式的重要目的就是减少旧代码的损耗提高维护效率)
  • 类适配器也可以用多重继承实现,继承双边的类然后桥接
  • 外观模式不改变接口,不进行封装,只是对一系列复杂的调用的接口简化整合,创造出新的简化用的接口,方便用户调用
  • 外观模式一般需要外观类能访问子系统的所有组件,然后才用简化的接口来对子系统的一些接口包装整合
  • 最少知识原则可以用来指导我们如何进行有效地封装解耦,划分出哪些方法是可以被包含到类里的,关键是对于任何对象,我们只该在以下范围内访问这个对象的方法:
    • 该对象本身
    • 被当作方法参数而传来的对象
    • 此方法创建或实例化的对象
    • 对象的组件
  • 复杂系统使用一重一重的外观来划分子系统是简化接口的好方法
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-04-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 未竟东方白 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档