1. 书摘
    1. 对象真正的威力不是继承而是“行为封装”
    2. 针对接口进行设计
    3. 设计模式不是单独存在的,而是需要与其他设计模式 协同工作以帮助你构建更健壮的应用程序
    4. 顿悟完全改变了我对设计模式的看法:设计模式 无法作为独立的条款使用,我应该把设计模式放 在一起使用
    5. 使用模式来帮助理解乃至描述问题领域,而不是 仅仅在理解了问题领域以后使用模式来创建一个 设计
    6. 基于模式的分析让你成为一个更有力,更高效的分析者。 因为它们让你更抽象地处理你的模型,因为它们向你 展示许多其他分析者积累的经验。
    7. 避免过早进入实现阶段, 在做之前先想
    8. 功能分解是处理复杂问题的一种自然方法。使用功能分解的难 题是:它不能帮助我们为未来可能发生的变化做准备,它不能 帮助我们的代码优雅的演变
    9. 试图同时关注过多的东西,就等于邀请错误与变化同时到来
    10. 魔鬼就生活在副作用中。函数的一个重要问题就是可能导致 很难发现的副作用
    11. 维护和调试的大多数时间不是花在修改错误上,而是花在 寻找错误和考虑如何避免在修改中再次引发副作用
    12. 使用功能分解时,变化的需求会让我软件开发和维护的成果大受打击。 我主要把精力集中在功能上。一个函数和数据结构的变化会影响到其他 的函数和数据,于是受影响的部分也要修改。这就像一个滚下山的
  2. 面向对象软件设计基础
    1. 面向对象范式以前
      1. 功能分解
        1. 局限性
          1. 处理变化
          2. 事物总是在变化
          3. 用户需求的变化
          4. 开发者对需求理解的变化
          5. 软件开发环境的变化
          6. 分析做得再好, 也无法知道用户的所有需求
          7. 低内聚,紧耦合
          8. 一个函数或数据结构的变化 会影响到其他函数和数据
          9. 只关注功能,会导致 “一处变化引起一连串变化”
    2. 传统的面向对象的观点: 寻找名词,数据封装, 焦点局限于如何实现对象
      1. 传统面向对象的局限性
        1. 过高的继承体系导致 紧耦合,低内聚
        2. 过早地对细节投入过 多的关心
          1. 处理细节总是比较容易
          2. 细节上的解决方案很明显
          3. 应该尽可能晚地投入到细节中
        3. 类爆炸
        4. 对继承的过度依赖会导致 更高的维护代价
    3. 面向对象范式
      1. 责任的转移
        1. 每个人对自己负责,而不是由 控制程序对他们负责
        2. 控制程序可以与不同类型的人对话
        3. 控制程序不需要知道学生在教室之 间移动的具体步骤
        4. 使用对象将责任转移到更局 部的范围
      2. 软件开发过程中的视角 by Martin Fowler
        1. 概念
        2. 规格
        3. 实现
        4. 从三个视角层次来考虑问题
      3. 在概念层次上通信 而在实现层次上执行
        1. 请求者不知道具体发生了什么, 只知道概念上发生了什么
      4. 对象
        1. 拥有责任的某种东西
        2. 对象应该对自己负责,并且这种 责任应该被清晰地定义出来
          1. 很多东西不需 要暴露给外界
        3. 概念层次:一个对象是一系列责任
        4. 规格层次:一个对象是一系列可以 被其他对象或该对象自己调用的方法
        5. 实现层次:一个对象是一堆 代码和数据
        1. 抽象类
          1. 定义了一组类可以做的事情
          2. 在概念层次上定义抽象类
      5. 封装
        1. 向用户隐藏一些东西
        2. 好处
          1. 使用更容易
          2. 实现可以在不考虑调用者的 情况下变更
          3. 对象外部的代码不知道对象内 部的情况
          4. 减少副作用
          5. 让对象为自己负更多责任, 控制程序需要负的责任更少
  3. 设计模式
    1. 产生于建筑学和人类学
      1. "质量可以客观评价吗?" --Christopher Alexander
      2. 对于任何特定的建筑物, 优秀的结构之间总有一些 相同之处
        1. 需要解决的问题的特点 中的共同点
      3. 结构不可以与它们要解决 的问题分离
      4. 观察解决相似问题的不同方案
      5. 模式:在某一个情境下的问题解决方案
    2. 是什么让设计优秀?
    3. 是什么让设计拙劣?
    4. 模式可以帮助你提升思考的层次
    5. 具体模式
      1. Facade
        1. 在原始系统的前面 构造了一个新的前 端接口
        2. 适用于
          1. 不需要使用原始复杂系 统的所有功能
          2. 希望包装或隐藏原有系统
          3. 编写一个新的类的代价<< 让所有 人学会使用该系统的代价
        3. 简化接口
      2. Adapter
        1. 将接口转换成为一个现有的接口
      3. Bridge
        1. 将抽象部分与实现部分分离, 使得它们都可以独立变化
        2. 避免抽象部分与实现部分的紧耦合
        3. 过度使用继承
          1. 由于得到了新的锤子,所有的东 西看起来都是钉子
          2. 根据对象的责任来考虑它们,而不 是根据它们的结构
          3. 对象的特点应该基于它们的责任 而不是它们包含的东西或它们 是什么东西
        4. 寻找初期设计的替代品
          1. 避免”分析瘫痪“
        5. 将注意力集中于模式的场景
          1. 模式尝试解决的问题
          2. 在确切知道如何实现设计模式 之前就判断出何时在问题领域中 使用它们
        6. 共同点/变化点分析
          1. 一种发现对象的新范式 比仅仅观察“名词/动词”更好的方法
          2. 共同点分析:寻找共同的元素,它们 帮助我们理解“家庭成员在哪些方面相同”
          3. 元素通过怎样的共同点 来定义它们的家族
          4. 寻找不太可能随时间变化的结构
          5. 变化点分析:“家族成员有什么不同”
          6. 只有在一个给定的共同点内, 变化点才有意义
          7. 捕捉有可能变化的结构
          8. 只有在由相关的共同点分析定义 的上下文中,变化点分析才有 意义
          9. 从体系结构角度
          10. 共同点分析为体系结构提供了耐久性
          11. 变化点分析让它适应各种应用的需要
          12. 变化点是问题领域中的具体情况,共同点 定义了问题领域中将具体情况捆绑在一起 的概念
          13. 共同的概念由抽象类实现
          14. 变化点分析发现的变化将由具体 类来实现
        7. 一条规则,一个地方
          1. 只在一个地方实现一条规则
          2. 如果你的程序中有做某一件事的规则, 只实现它一次
          3. 一次并且只有一次
          4. 系统必须与你希望沟通的任何事物沟通
          5. 系统不能包含任何重复的代码
        8. 在这个模式里有一个抽象部分 (以及派生类)和一个实现部分
          1. 设计实现部分的接口时,应该 考虑它必须支持的抽象类的 不同的派生类
        9. 关键特征
          1. 意图:将一组实现部分从另一组使用它们的对象中分离出来
          2. 问题:一个抽象类的派生类必须使用多种实现部分,但又不能 引起类数量的爆炸
          3. 解决方案:为所有的实现部分定义一个接口,让抽象类的所有派生类使用 这个接口
          4. 参与者与协作者
          5. Abstraction为正在实现的对象定义接口
          6. Implementor为特定的实现部分类定义接口
          7. Abstraction的派生类使用Implementor的派生类 而不必知道自己使用的特定的ConcreteImplementor
      4. Abstract Factory
        1. 意图:提供一个创建一系列相关或相互依赖对象 的接口,而无需指定它们具体的类
        2. Switch语句可能指出对抽象的需要
          1. 对多态行为的需要
          2. 抽象
          3. 存在着放错地方的责任
          4. 将责任交给另外的对象
        3. 跨接分析和设计的策略
          1. 发现并封装变化点
          2. 优先使用对象组合,而不是类继承
          3. 针对接口设计,而不是针对实现设计
  4. 创建优秀面向对象 设计的策略
    1. 针对接口编程
    2. 优先使用对象组合而非继承
    3. 找到并封装变化点
  5. 扩展视野
    1. 对对象的看法
      1. 传统:一堆 数据和方法 从实现视角对对象的观察
      2. 负有责任的某种东西 基于概念视角的定义
        1. 将注意力集中在对象应该做什么 而不仅仅是如何实现他们
          1. 分两步构建软件
          2. 建立一个初步的设计 不必担心涉及的任何细节
          3. 实现上面的步骤得到的设计
        2. 按照责任来考虑问题可以简化问题
          1. 帮助定义对象的公共接口
          2. 如果对象有某种责任,就一定 有某种途径要求它履行自己 的责任
          3. 并不对对象内容做任何暗示
        3. 关注于动机而不是实现
    2. 对封装的看法
      1. 传统:隐藏数据
      2. 隐藏任何东西. 封装可以被用于在行为中 包含变化
        1. 任何形式的隐藏
          1. 数据的封装
          2. 方法的封装
          3. 子类的封装
          4. 抽象类
          5. 其他对象的封装
          6. Adapter接口
        2. 提供了一种更好的切分程序的方式
          1. 封装层将成为要设计的接口
    3. 使用继承的方式
      1. 传统:特化和复用
        1. 为了复用的继承
      2. 对象分类
        1. 作为概念的继承
          1. 针对接口进行设计
        2. 一致地处理概念上相同的 不同具体类
    4. 发现并封装变化点
      1. 考虑你的设计中哪些是可变的
      2. 使用抽象类的引用来 进行组合
      3. 很多设计模式都使用 封装来创建对象之间的 分界层
        1. 设计者可以在分界层的一侧 进行修改,而不会对另一侧 产生影响,形成了松耦合
      4. 不仅仅在数据中包容变化 还可以在行为中包容变化
      5. 用对象处理行为中的变化点
      6. 使用被包含对象来提供 所需的行为
      7. 共同点/变化点以及抽象类
        1. 共同点关联于问题领域的概念视角
        2. 变化点关联于实现视角
        3. 规格视角处在中间
          1. 规格描述了如何与一组概念上 相似的对象沟通
          2. 实现层次上的抽象类和接口
        4. 规格视角和概念视角的关系
          1. 识别出用来处理这一概念下 所有情况的接口
        5. 规格视角和实现视角的关系
          1. 对于给定的规格,怎样实现 这一特定的情况
  6. 延伸阅读
    1. The Timeless Way of Building
    2. Object-Oriented Software Construction
    3. A Pattern Language
    4. Multi-Paradigm Design For C++
    5. Cognitive Patterns: Problem-Solving Frameworks for Object Technology
    6. Pattern Hatching
    7. The Greatest Salesman in the World
    8. The Mind Map Book: How to Use Radiant Thinking to Maximize Your Brain's Untapped Potential
    9. The Ethnographic Interview
    10. Knowledge Management Methods
  7. 用模式的方法来思考
    1. 面向模式设计
    2. 将注意力集中在高层关联上
    3. 从片段开始设计不是一个好的 设计方法
      1. 想把预先形成的片段累加起来以 构造任何拥有自然特征的事物, 这是不可能的
      2. 将预先成型的部分添加在一起 是不能得到优秀的设计的
    4. 根据在整体中的位置来定义每个部分
      1. 各部分需要与众不同,这样 它们可以利用自己独特的环境
    5. 在场景中设计片段
      1. 每个部分都将根据其在更 大的整体环境中的存在而 有其特定的形式
    6. 从最简单的角度观察问题, 然后添加附加的特征(差别) 逐渐让设计变得复杂,因为我们 加入了更多信息
      1. 每个模式都是对空 间进行区别的操作 即,在以前没有差异 的地方创建差异
    7. 模式独立于任何人而存在
    8. 设计遵循的原则
      1. 模式应该按照顺序, 一个一个使用
      2. 场景优先,首先使用那 些为其他模式创造场景的 模式
    9. 基于模式的设计途径
      1. 1. 为了理解需要实现的目标, 从对整体的概念性理解开始
      2. 2. 识别出在整体中出现的模式
      3. 3. 从为其他模式创造场景的模式开始
      4. 4. 应用这些模式
      5. 5. 对剩下的模式和中途发现的 模式,重复步骤3~5
      6. 6. 每次一个地应用这些模式 以创建场景,在这个场景中 对设计进行精炼
    10. 标准的设计方法经常让我们只见 树木,不见森林,因为我们过分将 精力集中于系统的细节上--类
      1. 在系统决策过程中,我们经常 陷入细节中而忘记了系统最大的 场景
      2. 细节会成为最大的视图周围 的一片阴云,让开发者集中精力于 小的,局部的决策
      3. 模式给了你一种语言,让你得以超越细节
  8. 用模式解决问题
    1. 1. 发现我在问题领域 中拥有的模式。这些是 需要分析的模式
    2. 2. 对于需要分析的 模式
      1. 挑选出为其他模式提 供最多场景的模式
      2. 在概念性最高的设计中 使用这个模式
      3. 识别任何可能出现的附加模式
    3. 3. 按需将细节添加到 设计中,扩展方法和类 定义
    4. 基本工具
      1. 寻找场景
        1. 首先关注对象 之间的关联
        2. 假设在需要的时候 可以构造出适合 这些关联的对象
        3. 推迟考虑如何实例化 我需要的对象
        4. 尽量减少脑子里 考虑的事情的数量
        5. 考虑你在系统中 需要什么,然后再关心 如何实现它
      2. 最高级模式约束其 他的模式
  9. 设计模式的原则 和策略
    1. 模式在局部和全局范围的作用
    2. 模式的机制以及作为它们基础 的原则和策略
    3. 开放-封闭的原则
      1. 对扩展是开放的
      2. 对更改是封闭的
      3. 将软件设计成这样: 在不修改代码的前提下对 我们的软件进行扩展
        1. 例:Bridge模式中就可以在不修改 任何现存的类的前提下加入新的实现 部分
    4. 从场景进行设计的原则
      1. 在设计片段出现的细节之前 先创建整体视图
      2. 识别可能性不等于必须要 跟着可能性走
        1. 可能性给了我对 问题领域的洞察力
      3. 设计模式帮助我看到 变化可能在哪里 发生,而不是哪个特定 的变化将发生
      4. 在不知道模式将被怎样使用 的前提(即不知道它的场景) 下就试图决定实现它,是傻 瓜才会作的事情
      5. 怎样作出设计决策
        1. 通常没有哪个实现方案天生 就比另一个更好
        2. 在哪种场合下这种选择会比另一 种选择更好?
        3. 这些场合哪些和我的问题领域 最相似?
    5. 包容变化的原则
      1. 我的继承体系中,类 的深度很少超过两层
        1. 决不让一个类包含 两件变化并以某种 方式耦合在一起的 事物
      2. 模式有效包容变化
      3. 模式识别变化 之间的关联
      4. 通过包容变化,可以 接纳未来可能出现的 变化
        1. 通过适当包容变化 ,我可以只实现那 些我需要的特性,而 不必牺牲未来的能力
        2. "试图确定并接纳所有的变化" 通常并不能造就好的系统-- 这种做法根本不能造就系统, 这叫作分析瘫痪
  10. 用设计模式处理变化
    1. 不同的模式会以相似的形式 处理变化点和新的需求
    2. 具体模式
      1. Strategy
        1. 最后的灾难往往 来源于短期行为 中不太好的决策
          1. 我们关注当下的 利害关系而忽略 长期问题
          2. "为变化进行设计"的开销 > "不考虑变化进行设计" ?
        2. 预料到变化将会发生, 并观察它们将在哪里 发生,但不会预测变化 确切的种类
        3. 考虑你的设计中哪 些是可变的
          1. 与关注引起重新设计 的原因相反
          2. 不是考虑什么会使你的设计 改变
          3. 考虑什么会变化却又不引起 重新设计
          4. 封装变化的概念
        4. 提高内聚度,对灵活 性有帮助
        5. 在一个抽象类中封装算法 并交替使用这些算法的模式 就是Strategy模式
          1. 意图:定义一系列的算法, 把它们一个个封装起来, 并且使它们可相互替换。 使算法可以独立于使用它 的客户而变化。
          2. 原则
          3. 对象拥有责任
          4. 责任的不同特定实现 通过使用多态来表现
          5. 将问题领域中发生的 行为彼此分离,即,使 它们解耦
          6. 将算法的选择和算法的 实现相分离,让客户可以 根据场景作出选择
          7. 封装业务规则
        6. 参与者和协作者
          1. Strategy
          2. ConcreteStrategies
          3. Context
      2. Decorator
        1. 根据责任进行分解
          1. 如何实现提供新 功能的对象
          2. 如何为每种特定情况 将对象组织起来
          3. 将"Decorator对象的实现" 与"判断如何使用它们的对象" 相分离
          4. 每个Decorator对象只 关心自己添加的功能,而 不关心自己如何被添加到 对象链中
        2. 典型实现方式
          1. 使用工厂模式, 在某些配置信息 的基础上实例 化对象链
        3. 解决方案: 扩展一个对象的功能 而不必借助于子类化
        4. 意图:为一个对象动 态连接附加的职责
        5. 参与者/协作者
          1. Component
          2. ConcreteComponents
          3. Decorator
      3. Singleton/ Double-Checked Locking
        1. Singleton-单线程
        2. Double-Checked Locking- 多线程
      4. Observer
        1. 意图:在对象间定义一对多的依赖关系
        2. 问题:当一个对象发生变化 需要向一系列对象发出通知, 而这个对象的列表是不断变化的
        3. 解决方案:将监视某个事件的责任 委托给一个中心对象,Subject
        4. 参与者/协作者
          1. Subject
          2. Observer
        5. 为了能让所有的观察者型 对象实现Observer接口, 有时需要和Adapter模式
        6. 不是用于所有的依赖关系 而是用于变化的或动态的 依赖关系
        7. 一个观察者可能只需要处理事件 的某种特定情况
          1. 观察者将另外的 通知过滤掉
          2. 将过滤通知的责任转 移给Subject,结合 Strategy模式 每个观察者在注册时 都将合适的策略对象交 给Subject对象
      5. Template Method
        1. Template Method不是 组合在一起的Strategy 模式
          1. 几个Stragety模式 彼此连接出现的情况 很少见,那样的设计会 使灵活性降低
        2. 先定义步骤的顺序,然后重载那些 需要改变的步骤
      6. Factory Method
        1. 意图:定义一个用于创建对象 的接口,让子类决定实例化 哪一个类。Factory Method使 一个类的实例化延迟到其子类
        2. 在定义框架的时候很常用
          1. 框架存在于一个 抽象的层次上
          2. 框架不知道,也不 应该关心特定对象 的实例化
          3. 将特定对象的实例 化推迟给框架的用户
      7. 分析矩阵
        1. 问题不会是有条不紊而 行为良好的
        2. 总会有一引起没有组织好的 异常和变化出现,破坏我们精 心设计的模型
        3. 弄清系统中的变化点 然后分析识别我应该在设计 中使用的模式
          1. 1.识别某种情况下最重要的特征,并将它 们组织成一个矩阵。用矩阵表现的概念 为每个特征作上标记
          2. 2. 识别其他的情况 根据需要对这个矩阵进行扩展。 独立于其他的情况来分别处理每种情况
          3. 3. 用新的概念扩展分析矩阵
          4. 4.用矩阵的行来确定规则
          5. 5.用矩阵的列来确定特殊情况
          6. 6. 从这种分析中确定模式
          7. 7.开发一个高层设计
        4. 分析矩阵不太可能捕捉一个问题领域中 所有的问题特点
        5. 当客户给我太多特定情况, 脑子中容不下整体视图时, 分析矩阵就很有用了
  11. 终点和起点
    1. 面向对象原则的新视角, 基于对设计模式的理解
      1. 对象是负有定义良好 的责任的东西
      2. 对象对自己负责
      3. 封装意味着任何 形式的隐藏
        1. 数据隐藏
        2. 类隐藏
          1. 隐藏在抽象类和接口后面
        3. 实现隐藏
      4. 使用共同点/变化点分析 抽象出行为和数据中的变 化点
      5. 针对接口进行设计
      6. 把继承考虑为一种封装 变化的方法,而不是为现有 对象制造特殊情况
      7. 把变化点封装在一个类中,并 使之与这个类中的其他变化点 相分离
      8. 力求松耦合,高内聚
      9. 绝对细心地应用 "一次并且只有一次" 规则
    2. 设计模式如何帮助我们封 装实现
      1. 大多数模式提供了隐 藏特定实现的途径
      2. 隐藏实现的价值
        1. 让开发者可以轻易地添加 新的实现,因为客户不知道 现在的实现是怎样工作的
    3. 共同点/变化点分析和设计模式, 如何帮助我们理解抽象类
      1. 使用共同点/变化点分析 来实现很多模式
      2. 寻找共同点可以帮助 我们发现问题领域中 出现的模式
    4. 根据涉及的责任对问题 领域进行分解
      1. 共同点/变化点分析 确定了我的概念视角 和实现视角
      2. 如果只考虑共同点和使用共同点的对象 可以从一个不同的角度来考虑问题-- 按照责任的分解
      3. 将问题领域分解为责任
        1. 然后定义实现这些责 任需要的对象
      4. 设计者不应该在知道自己需要 的所有对象之前担心如何实例 化对象
      5. 特定的模式经常会 协助我们考虑如何 分解责任
    5. 确定对象之间的关联
      1. 一个模式描述了一个 特定场景中特定问题 的约束,动机和关联 并给了我们一种方法 论来讨论这些问题
    6. 设计模式和场景化设计
      1. 针对接口和多态进行设计
        1. 根据场景进行设计
        2. 抽象类的接口定义了场景 它的所有派生类必须在这 个场景内实现
    7. 学习模式的途径
      1. 这个模式中隐藏了什么实现?
        1. 从而让你可以改变实现
      2. 这个模式中出现了什么共同点?
      3. 这个模式中对象的责任是什么?
      4. 这些对象间有什么关联?
      5. 这个模式如何成为“根据场景进行 设计”的范例?
    8. 观察模式的特点
      1. 它们封装什么?
      2. 它们如何使用共同点/变化点分析?
      3. 它们如何按照责任对问题领域 进行分解?
      4. 它们如何确定对象之间 的关联?
      5. 它们如何阐述场景 化设计