可以将这本书看成"四人帮"设计模式的一个选择性展开说明, 作者认为设计模式里面的内容太晦涩, 太抽象, 学术味太重. 因此需要这么一本教材性质的模式书, 但是作者又没有全部把23种模式都拖出来论述一番, 而是按照自己的方式有选择性的进行重新的组织, 给人的感觉是前面的内容还可以, 后面的只能算凑合了. 整本书采用Java作为讲解语言, 因此可以看成"设计模式解析Java版". 在我看来整本书在围绕封装变化, 隔离实现与使用来说事儿. 让读者从这两方面去理解设计模式. 算是一种比较容易入门的角度吧. 另外作者貌似对继承深恶痛绝, 大声疾呼优先使用组合, 虽然这个是常识, 但是鄙人时不时会犯这个错. 也算是对设计模式的一个复习, 毕竟平时用到的设计模式不多, 另外从这本书同时得到的一个观念是: 使用模式不仅仅只是为了复用, 往往为了追求复用导致过度使用继承.
以下算是对自己比较有意义的观点摘录:
内聚性描述的是一个例程内部组成部分之间的相互关系的紧密程度, 而耦合性描述的是一个例程与其他例程之间的联系的紧密程度.
内部完整(高内聚), 而与其他例程之间的联系则是小巧, 直接, 可见, 灵活的(松耦合).
在维护和调试过程中, 改正隐错只需要花费很少的时间, 维护和调试的绝大多数时间都被用于努力弄清代码的运作机理, 寻找隐错和防止不良副作用上了, 真正的改正时间却相当短.
开发过程中的视角:
- 概念视角:软件要负责什么?
- 规约视角:怎么使用软件?
- 实现视角:软件怎么履行自己的职责?
组合: 被包含者是包含者的一部分, 比如汽车中的发动机
聚合:有一个集合, 集合中的东西可以独立存在, 比如机场上的飞机
UML中的几种关系图:
- A◇----B : A聚合了B, B是A的一部分.
- A◆----B: A是由B组成的, A包含B类型的对象.
- A--->B: A依赖B, A使用B
类图可以表示类之间的静态关系, 换句话说, 类图不能表示任何活动.
转移职责是面向对象程序设计基本原则之一.
寻找平衡必须成为做出设计决策的第一要务.
一种更有效的对象定义是从概念视角出发, 对象是具有职责的一个实体, 这些指责定义了对象的行为, 这样有助于我们关注对象的意图行为而不是对象如何实现, 这种理解使我们能够以两个步骤构建软件:先做出一个初步的设计, 不用操心所有相关的细节; 实现该设计.
面向对象泛型的早期提倡者曾经将"类的服用"作为巨大优势之一大力鼓吹(本人应该算是一个受害者), 这种复用通常是通过先创建基类, 然后从这个基类出发派生新类而实现的. 这种方式可能带来的问题:
可能导致弱类聚
减少复用的可能性
无法根据变化很好的伸缩(当有变化时, 可能需要不断的子类化)
发现变化并将其封装
当一个类处理越来越多的不同的变化(比如通过开关变量)时, 代码的内聚性就会变得很差. 也就是说, 它所处理的特殊情况越来越多, 可理解性就越差.
找出变化的地点, 称为"共性分析"; 然后找出如何变化, 称之为"变性分析"
共性分析寻找的是不可能随着时间而变化的结构, 而可变性分析则要找到可能变化的结构. 可变性分析只在相关联的共性分析定义的上下文中才有意义, 从架构的视角来看, 共性分析为架构提供长效的要素, 而可变性分析则促进它适应实际使用所需.
比从名词和动词入手来做面向对象分析更好的一种做法是在创建对象时使用共性和可变性分析.
共性分析与问题领域的概念视角是相互关联的, 而可变性分析与特定情况的实现是相互关联的. 规约视角则位于其中, 共性和可变性要涉及这个视角.
Strategy模式
一般来说, 只要在分析过程中听到需要在不同时间应用不同业务规则, 我就会考虑使用Strategy模式处理这种变化的可能性.
Strategy模式要求所封装的算法(业务规则)应处在使用它们的类(Context)之外, 这意味着Strategy所需要的信息必须要么传递给他们, 要猛以某种其他形式获得.
Bridge模式
Bridge模式是最难理解的模式, 部分原因是它功能非常强大, 适用于很多场合, 而且, 它还与常见的用继承来处理特殊情况的方式背道而驰, 但是它遵循设计模式领域两大原则的极好例子: 找出变化并封装之; 优先使用对象聚合, 而不是类继承.
通过子类化处理变化, 从已有类派生新类, 这是对对象"is-as" 性质的过度关注, 程序员旺旺在巨大臃肿的类层次中创建对象, 这种层次开始时可能还能工作, 但是随着时间的推移将变得越来越难以维护.
应该有选择的使用继承, 这样才能发挥其优势. 应该从"为每种变化使用不同的特化"到"将变化转义到使用或拥有这种变化变化的对象中"转变.
原则总是适用的, 而模式只是在某些场景下才适用.
在Shape的例子中, 使用Bridge模式之后的样子与使用继承的情况非常类似, 但是最大的区别在于, 方法现在被放在了不同的类中. Bridge模式将实现看成对象之外的东西, 看成由对象所使用的东西, 这样就使变化隐藏在实现中, 与调用程序隔离了, 从而提供了极大的自由.
使用Bridge之前的样子
使用Bridge之后的样子
Abstract Factory模式
switch语句本身常常说明:需要多态行为;存在错放. 应该考虑用一种更通用的解决方案, 比如抽象代替witch语句或者将职责赋予其他对象.
Client让Factory来负责跟踪应该使用哪些对象, 虽然我们仍然需要为Factory编写选择代码, 但是问题已经根据职责分解了, Client的 是了解如何使用合适的对象, Factory的职责是决定哪些对象合适. 这样做同样可以加强内聚性: Factory所作的就是创建合适的对象, Client只负责使用这些对象.
Abstract Factory模式将使用哪些对象的规则与如何使用这些对象的逻辑分离开来, 当问题域中存在的对象, 而且每组都用于不同情况时, 就应该使用
继承层次中最好不要超过两层
不要让一个类封装两个要变化的事物, 除非这些变化都耦合在一起.
Decorator模式
Decorator模式帮我们将问题分为两个部分:如何实现提供新功能的对象;如何为每种特殊情况组织对象.
这样可以将Decorator对象的实现与决定如何使用Decorator对象分离开来, 从而提高了内聚性, 因为每个Decorator对象只用关心自己添加的功能, 而无需关心自己如何被添加到对象链中.
Observer模式
当依赖关系固定时, 引入Observer模式可能只会增加复杂性. 如果需要得到某事件通知的对象列表是变化的, 或者有条件的, 那么Observer模式更具价值.
应该在确定了对象是什么最后再定义工厂
对于对象的创建和管理, 有一条很好的通用规则可以遵守: 对象应该要么创建或管理其他对象, 要么使用对象, 而不应该兼而有之.
一般而言, 模式有助于我们遵循开闭原则, 即需要修改时, 应该添加新代码, 而不是修改老代码, 这能够降低维护成本.
工厂并不能完全消除工作量, 但是它能够在必须处理新情况时, 避免使已经很复杂的代码更加复杂.
工厂是为了将使用与构造分离.
Object Pool模式
Object Pool模式使用场景:在创建对象比较昂贵, 或者对于特定类型能够创建的对象数量有限时.
有一个创建一个对象的方法, 这就叫做Factory Method.
对于系统中的任意两个实体A和B, 应该将他们之间的关系限制为A使用B, 或者A创建/管理B, 但是两种关系永远不要同时存在!