cuixiaorui/chunquchunyoulai

阅读《实现模式》

cuixiaorui opened this issue · 1 comments

阅读《实现模式》

实现模式

价值观

核心

  • 灵活
  • 沟通
  • 简单

定义

  • 大方向(抽象)

原则

定义

  • 是价值观和模式之间的桥梁

核心

  • 局部化影响

    • 变化时只影响局部
  • 最小化重复

    • 把程序拆分的更小来减少重复
  • 将逻辑与数据绑定

  • 对称性

    • 举例

      • add <--> remove
    • 概念上的对称

  • 声明式表达

    • 尽可能声明式地表达出意图
  • 变化率

    • 类似单一职责

      • 把需要一起变化的功能放到一起

        • 高内聚

定义

  • 用一个类来表示”这些数据应该放在一起,还有这些逻辑也应该和他们在一起“

把数据和逻辑关联起来

模式

  • 简单的超类名

    • 位于继承体系根上的类应该有简单的名字,用以描绘它的隐喻
    • 类名要简短和表现力
    • 隐喻
  • 限定性的子类名

    • 子类的名字应该表达出它与超类之间的相似性和差异性

    • 描述类像什么

    • 说明和其他子类之间的关系

    • 通常可以在超类的基础上扩展一两个词即可

    • 特殊:本身代表了重要的概念

      • 需要像对待超类一样
  • 抽象接口

    • 将接口与实现分离

    • 针对接口编程,不要针对实现编程

      • 接口:一组没有实现的操作
    • 当真正需要这种灵活性的时候在引入接口

      • 接口是有成本的
  • interface

    • 用 java 的 interface 机制来表现不常变化的抽象接口

    • 命名

      • 和类一样命名
      • 添加 I 前缀
    • 这是我要完成的任务,除此之外的细节不归我操心

    • 改动会影响所有之前的设计

    • 核心定义

      • like a
  • 抽象类

    • 用抽象类来表现很可能变化的抽象接口

    • 超类的引用可以在运行时替换为任何子类的对象

    • 和 interface 的区别

      • interface 改动的话会影响所有设计

      • 抽象类的话 只需要提供基础的实现,那么不会影响到全局

        • 用 abstract 关键字来修饰的话 如果要使用这个类,就必须做一些实现的工作
    • interface 和抽象类不互斥

      • 提供一个接口:可以使用这些功能

        • 对外
      • 提供一个超类:这是一种实现方式

        • 对内
    • 核心定义

      • is a
  • 有版本的 interface

    • 引入新的子 interface ,从而安全的对 interface 进行扩展
    • 新增加一个接口继承之前的接口来扩展需求而不破坏之前的设计
  • 值对象

    • 这种对象的行为就好像数值一样

    • 值不可变的对象

    • 使用

      • 区分出”状态的世界“和”值得世界“
      • 组合使用状态可变的对象和值对象
      • 改变值得时候总是返回一个全新的对象,使用者负责存储
  • 特化

    • 清晰地描述计算过程中相似性与差异性的相互作用,可以让程序更容易阅读、使用和修改

    • 差异性

      • 相同的逻辑处理不同的数据
      • 不同的逻辑处理相同的数据
  • 子类

    • 用一个子类表现一个维度上的变化

    • 共享实现

      • 继承
    • 声明一个子类

      • 这些对象与那些对象很类似,只除了……
    • 局限性

      • 共享实现只能用一次
      • 使用者必须首先理解超类
      • 对超类的修改颇有风险
    • 使用

      • 超类中的逻辑必须进行彻底地划分到每个方法只做一件事

        • 方法足够的小,那么子类就容易重写

          • 有点模板模式的意思
  • 实现器

    • 覆盖一个方法,从而表现一种计算上的变化

    • 多态之美

      • 给系统开启了变化的机会
  • 内部类

    • 将只在局部有用的代码放在一个私有的类中
    • java 的概念
    • 需要把一部分计算逻辑包装起来,但又不想新建一个文件来安置全新的类
  • 实例特有的行为

    • 每个实例的逻辑都有不同
    • 一个类的所有实例逻辑都是一样的
    • 实例特有的行为,需要在对象创建之初就确定下来,之后不再改变
  • 条件语句

    • 明确指定条件,以表现不同的逻辑

    • 实现实例特有的行为

      • 方式

        • if/else
        • switch
      • 好处

        • 所有的逻辑仍然在同一个类里,阅读者不必四处寻找所有可能的计算路径

          • 简单
          • 局部化
      • 缺点

        • 除了修改对象本身的代码之外,没有其他办法修改它的逻辑

          • 不灵活
      • 解决

        • 条件逻辑变成消息

          • 发送给子类或者委派
  • 委派

    • 把操作委派给不同类型的对象,以表现不同的逻辑

    • 不变的逻辑放在发起委派的类中,变化的逻辑交给被委派的对象

      • 多态的使用方式
    • 委派对象可以保存在实例变量里

      • 可插拔对象
    • 实现代码共享

  • 可插拔的选择器

    • 通过反射来调用方法,以表现不同的逻辑

      • 反射 java.class 对象
  • 匿名内部类

    • 在方法内部创建一个新对象,并覆盖其中的一两种方法,以表现不同的逻辑
    • java 特有的
    • 可以创建只在一处使用的类
  • 库类

    • 如果一组功能不适合放进任何对象,就将其描述为一组静态方法

    • 某些功能放在哪个对象中都不合适,那么就放到库类里(类似 utils)

      • 保存为静态方法
    • 少用

      • 尽可能的使用类

状态

对象包装了行为和状态

  • 行为暴露给外部世界
  • 状态为行为提供支持

模式

  • 状态

    • 使用可变的值进行计算

    • 管理状态

      • 把相似的状态放一起,不同的状态要分离

      • 相同相似性

        • 两个状态总是被同时使用
        • 同样的生命周期
  • 访问

    • 限制对状态的访问,从而保持灵活性
  • 直接访问

    • 直接访问对象的内部状态

    • 使用

      • 只在访问器和构造器中使用
      • 只在类中使用
      • 以上两种规则并不是绝对的
    • 优点

      • 清晰
    • 缺点

      • 灵活性低

      • 属于实现细节,层面低于编程时通常的思考层面

        • 无法表达当前的意图
  • 间接访问

    • 通过方法来访问状态,从而提高灵活性

    • 使用

      • 允许在类中直接访问,其他的使用者必须间接访问
  • 通用状态

    • 把状态保存在一个字段中,使得该类的所有对象都拥有这些状态

      • 新建一个类来保存这些通用状态
  • 可变状态

    • 如果各个实例拥有不同的状态,那么将这些状态放入一个 map,并将 map 保存在实例变量中
  • 外生状态

    • 某些特殊用途的状态可以放入一个map,并由状态的使用者负责保存
  • 变量

    • 变量提供了访问状态的命名空间
  • 局部变量

    • 具备变量保存的状态只在单一作用域有效

    • 信息最小扩散原则

      • 哪里使用就声明在哪里
    • 角色

      • 收集器

        • 收集稍微需要的信息,最后最为返回值传出
      • 计数

      • 解释

        • 解释复杂的表达式
      • 复用

        • 表达值的值不会变化,那么可以保存起来用来复用
      • 元素

        • 迭代遍历的时候使用
  • 字段

    • 字段保存的状态在对象的整个生命周期有效

    • 角色

      • 助手

        • 存放其他对象的引用,该对象会被当前对象的很多方法用到
      • 标记

        • boolean 型的标记

          • 如果是 true 就这样
          • 如果是 false 就那样
      • 策略

        • 策略模式保存不同的策略
      • 状态

        • 不是太明白
      • 组件

        • 保存所在对象 拥有的对象或者数据
  • 参数

    • 参数在一个方法被调用之初描述当时的状态
    • 参数是将对象联系起来的细线
  • 收集参数

    • 传入一个参数,用于收集来自多个方法的复杂结果
  • 参数对象

    • 把常用的长参数列表打包成一个对象
  • 常量

    • 不变的状态应该保存为常量
  • 按角色命名

    • 根据变量在计算中扮演的角色为它们命名
  • 声明时的类型

    • 为变量生命一个尽可能通用的类型
  • 初始化

    • 尽可能以声明性的方式对变量进行初始化
  • 及早初始化

    • 在创建实例的同时初始化字段
  • 延迟初始化

    • 如果字段的求值动作开销高昂,可以考虑在第一次使用之前才初始化
    • 性能很重要

行为

控制流

  • 将运算表达成一系列的步骤

主体流

  • 明确表达控制流的主体
  • 用异常和卫述句去表达不寻常的后者错误的情形

消息

  • 通过发送消息来表达控制流

选择性消息

  • 通过变动一条消息的实现者来表达选项

双重分发

  • 通过在两条轴线上变动消息的实现者来表达级联的选项

分解性消息

  • 将复杂的计算分解成具有内聚性的块

反置性消息

  • 通过向同一个接受者发送消息序列,令多个控制流形成对称

邀请性消息

  • 通过发送可以用不同方式实现的消息,邀请未来的实现变体

解释性消息

  • 发送消息去解释一段逻辑的意图

异常流

  • 尽可能清晰地表达非寻常的控制流,而不干扰对主体流的表达

卫述句

  • 用尽早返回来表达局部的异常流

异常

  • 用异常来表达非局部的异常流

已检查异常

  • 通过明确声明来保证异常被捕获

异常传播

  • 传播异常,根据需要转换异常,以便使其包含的信息合乎捕捉者的要求

改进框架

修改框架而不修改应用

  • 复杂与简单在某一点达到平衡,即有可以改进的余地,又方便使用
  • 使用范围的大小在某一点达到平衡,即可以改进,又具有使用价值

不兼容的更新(增量式更新)

  • 并行架构

    • 增加新api的同时也维护废弃的api
  • 增加一个过渡式的发布

鼓励可兼容的变化

  • 减少可见的细节数量,只暴露那些变化可能性较小的细节

  • 交付可用的功能,又保留更改设计的自由

  • 兼容性

    • 向后兼容

      • 客户端仍然可以调用旧的api
    • 向前兼容

      • 可以向客户端中传入新形式的对象,而他们还可以像旧对象一样工作
  • 程序类库

    • 库类是一种简单的api形式,经得起未来的考验

    • 提供一系列的静态方法

    • 问题

      • 客户代码只能改变他们自己发送给框架的数据,缺无法更改逻辑
      • 能够被轻松表达出来的概念数目是有限的
  • 对象

    • 使用方式

      • 实例化

        • 直接 new 对应的对象
      • 配置

        • 灵活
        • 我个人理解为给一个配置对象
      • 实现

        • 客户可以创建自己的类供给框架使用
        • 保证接口一致即可
        • 框架必须保证接口不变,框架承担了更多的责任
    • 抽象

      • 接口

        • 接口所记录的细节少
        • 适合表示不经常改变的抽象
      • 超类

        • 可以比接口描述更多细节
        • 向超类中增加操作不会破坏已有的代码
        • 只能继承一个框架类
        • 遵循最小暴露原则
    • 创建方式

      • 无对象创建

      • 构造器

        • 稳定的类
      • 工厂方法

        • 容易发生变化的类
      • 工厂对象

    • 方法

隐喻

  • 框架是在一个领域内所有有价值的功能的交集,而不是并集

    • 满足我得用户的常见需求,而不是他们各自独有的需求

容器

隐喻

  • 多值变量

    • 一个变量引用一个容器,就像它同时引用了多个对象
  • 容器就是对象

  • 数学集合

要点

  • 概念

    • 大小
    • 有序性
    • 唯一性
  • 选择容器

    • 影响性能

接口

  • array

  • iterable

    • 迭代
  • collection

  • list

  • set

  • sortedSet

  • map

方法

组合方法

  • 通过对其他方法的调用来组合出新的方法
  • 先让代码正常工作,然后再决定该怎么安排它的结构

揭示意图的名称

  • 在名称上反映出方法打算做什么事

方法可见性

  • 尽可能降低方法的公开程度

方法对象

  • 把复杂的方法变成对象

覆盖方法

  • 通过覆盖一个方法来表达特殊化

重载方法

  • 为同样的计算提供不同的接口

方法返回类型

  • 尽可能声明一个泛化的返回类型

方法注释

  • 通过方法注释来表达不容易从代码中读出的信息

助手方法

  • 增加小的、私有的方法来使计算的主体部分表达得更简明

调试输出方法

  • 用 toString() 输出有用的调试信息
  • 其他用户的字符串表示放在其他方法或单独的类中

转换

  • 清晰地表达从一个类型的对象到另一个类型的对象的转换

转换方法

  • 对于简单的、有限的转换,在源对象中提供一个方法,让它返回转换后的对象

转换构造器

  • 对于大多数转换,在目标对象的类中提供一个方法,让它接受一个源对象作为参数

创建

  • 清晰地表达对象的创建

完整的构造器

  • 编写一个构造器,让它返回完全塑造好的对象

工厂方法

  • 将较复杂的创建表达成类中的一个静态方法,而非构造器

内部工厂

  • 将需要进一步解释或者日后需要调整的对象创建封装进一个助手方法

容器访问器方法

  • 为容器的限制性访问提供方法

布尔值 setting 方法

  • 如果有助于沟通,为布尔值的两种状态分别提供一个设置方法

查询方法

  • 通过名为 asXXX 的方法返回布尔值

相等性判断方法

  • 同时定义 equals() 和 hashCode()

getting 方法

  • 在特殊情况下提供对一个字段的访问,用一个方法返回该字段

setting 方法

  • 在更罕见的情况下提供一个设置字段的方法

安全副本

  • 对传入或传出访问器方法的对象进行复制,避免混淆

XMind: ZEN - Trial Version