《Head First设计模式》读书笔记 —— 设计模式入门&策略模式

《Head First设计模式》读书笔记 —— 设计模式入门&策略模式

《Head First设计模式》读书笔记

相关代码:Vks-Feng/HeadFirstDesignPatternNotes: Head First设计模式读书笔记及相关代码

为什么学设计模式

有些人已经解决你的问题了

为何以及如何利用其他开发人员的经验和只会解决类似的问题

“把模式装进脑子里,然后再你的设计和已有的应用中,寻找何处可以使用它们”

代码复用->经验复用

Q&A:

Q:是不是一定要先把系统做出来,再看看有哪些地方需要变化,然后才回头去吧这些地方分离&封装?

A:不尽然,通常在设计系统时,预先考虑到有哪些地方未来可能需要变化,于是提前在代码中加入这些弹性。你会发现,原则与模式可以应用在软件开发生命周期的任何阶段。

Q:“用一个类代表一个行为”是否有些奇怪。类不是应该代表某种“东西”吗?类不是应该同时具备状态“与”行为吗?

A:OO系统中,类代表的东西一般都是既有状态又有方法。但是当“东西”是个行为时,即使是行为也可以有状态和方法

例如:飞行行为有飞行高度、速度等属性

Q:软件开发完成“前”以及完成“后”,哪个需要花费更多时间呢

A:我们总是需要花许多时间在系统的维护和变化上,比原先开发花的时间更多,所以我们应该致力于提高可维护性和可扩展性上的复用程度

Q:如果设计模式这么棒,为何没有人建立相关的库呢?那样我们就不必自己动手了

A:设计模式比库的等级更高。设计模式告诉我们如何组织类和对象以解决某种问题。而且采纳这些设计并使它们适合我们特定的应用,是我们责无旁贷的事

Q:库和框架不也是设计模式吗

A:库和框架提供了我们某些特定的实现,让我们的代码可以轻易地引用,但是这些并不是设计模式。有些时候,库的框架本身会用到设计模式。当你了解了设计模式,会更容易了解这些API是围绕设计模式构造的。

本节例子

我们有一个模拟鸭子游戏,鸭子有游泳、呱呱叫等行为

设计了一个鸭子超类(Superclass),并让各种鸭子继承此超类

但是当我们想为鸭子添加新行为时,例如飞行,我们直接在超类中添加fly(),会发生什么呢?你的橡皮鸭子可能也会飞到天上!

那我们该怎么办呢……

分开变化和不会变化的部分

HeadFirst设计原则1 :找出应用中 可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。

把会变化的部分取出并“封装”起来,以便以后可以轻易地改动或扩充此部分,其他部分不会受到影响

结果:代码变化引起的不经意后果变少,系统变得更有弹性

例如:鸭子的行为可以从鸭子类中抽离出来

鸭子:红头鸭、绿头鸭、橡皮鸭、木头鸭……

行为:叫声、飞行……

如果不同鸭子类直接实现接口,重复代码仍然过多

前提:接口不能有实现代码

举例:红头鸭、绿头鸭都有共同的飞行行为

针对接口编程

HeadFirst设计原则2 :针对接口编程,而不是针对实现编程。

实质:“针对超类型(supertype)编程”

变量的声明类型应该是超类型,通常是抽象类或接口

-> 该超类型的实现类都可以指定为该变量

-> 声明类时不用理会以后执行时的真正对象类型

关键在于利用多态,使程序可以针对超类型编程,执行时根据实际状况执行真正的行为,不会被绑死在超类型的行为上

解决方案:取出易于变化的部分,将鸭子行为和鸭子类独立出来,让行为类实现行为接口。

鸭子类不需要知道行为的实现细节

可以在“运行时”动态地“改变”鸭子的行为

整合行为

上例中,鸭子将飞行和呱呱叫的动作“委托”(delegate)别人去处理,而不是使用定义在Duck类(或子类)内的呱呱叫和飞行方法

在类中加入行为的实例变量

实现调用行为类方法的方法

public class Duck {

// 鸭子引用实现行为接口的对象

QuackBehavior quackBehavior;

public void performQuack() {

// 鸭子不亲自处理行为,而是委托给行为对象

quackBehavior.quack();

}

}

设定行为实例变量

在类的构造器中指明其行为具体实例

这其实还是对具体实现编程,后续内容中会通过更多其他模式来修正这一点

动态设定行为

除了在构造器中设定行为,还可以通过设定方法(setter method)来设定鸭子的行为

通过传入行为对象实例,来修改行为

public void setFlyBehavior(FlyBehavior fb) {

flyBehavior = fb;

}

public void setQuackBehavior(QuackBehavior qb) {

quackBehavior = qb;

}

封装行为的大局观

我们对类类的行为的认识,从“一组行为”到“一簇算法”

“有一个”可能比“是一个”更好

HeadFirst设计原则3 :多用组合,少用继承

如本例:将多个类结合起来使用,叫“组合”(composition),鸭子的行为不是继承来的,而是和适当的行为对象“组合来的”

使用组合建立的系统有很大的弹性,不仅可将算法族封装成类,更可以“在运行时动态地改变行为”,只要 组合的行为对象符合正确的接口标准即可

策略模式

HeadFirst设计模式1-策略模式

在上面的例子中,我们使用策略模式让让子系统变得更好

策略模式定义了算法族,分别封装起来,让它们之间可以相互替换,此模式让算法的变化独立于使用算法的客户

共享词汇

设计模式让你和其他开发人员之间有共享的词汇,一旦懂得这些词汇,和其他开发人员之间沟通就容易,也会促使哪些不懂得程序员想开始学习设计模式。设计模式也可以把你的思考架构的层次提高到模式层面,而不是仅停留在琐碎的对象上

共享模式词汇的威力

使用模式和他人沟通时,其实“不只是”和他人共享“行话”而已

共享的模式词汇“威力强大”

交流的不只是模式名称,而是一整套模式背后锁象征的质量、特性、约束

模式能够让你用更少的词汇做更充分的沟通

将说话的方式保持在模式层次,可让你待在“设计圈子”久一点

保持在设计层次,不会被压低到对象与类的琐碎上

共享词汇可帮你的开发团队快速充电

共享词汇能帮助初级开发人员迅速成长

如何使用设计模式

库和框架无法帮助我们将应用组织成容易了解、容易维护、具有弹性的架构,所以需要设计模式

设计模式不会直接进入代码,而是在大脑中有充分储备后,就能开始在新设计中采用他们,或是重写旧代码

想构建出弹性的、可复用的、可维护的系统,需要通过不断地艰苦实践,而设计模式就是收集整理出来的这些构造OO系统的隐含经验

当找不到模式时:有一些面向对象原则,适用于所有的模式,当你无法找到适当的模式解决问题时,采用这些原则可以帮助你。

建立可维护的OO系统,要诀就在于随时想到系统以后可能需要的变化以及应付变化的原则

总结

OO基础:

抽象

封装

继承

多态

OO原则:

封装变化

多用组合,少用继承

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

OO模式:

策略模式——定义算法簇,分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用算法的客户

要点:

只知道OO基础不足以设计出良好的OO系统

良好的OO系统需要具有可复用、可扩充、可维护三个特性

模式让我们建造出具有良好OO设计质量的系统

模式被认为是正确的OO设计经验

模式不是代码,而是针对设计问题的通用解决方案。可以把它们应用到特定的应用中

模式不是被发明,而是被发现

大多数的模式和原则,都着眼于软件变化的主题

大多数的模式都允许系统局部改变独立于其他部分

我们常把系统中会变化的部分抽出来封装

模式让开发人员之间有共享的语言,能够最大化沟通的价值

相关推荐