《Head First 设计模式》阅读

来源:互联网 发布:php 数值比较 编辑:程序博客网 时间:2024/05/29 16:40

1.设计模式其实就是过去人们面对同样的软件设计问题所学来的经验。
2.学习的重点:

  • 事关紧要的模式
  • 何时使用某个设计模式,为什么使用该模式
  • 如何在自己的设计中马上采用这些设计模式
  • 何时不该使用设计模式,如何避免对设计模式狂热
  • 模式是基于哪些面向对象设计原则设计出来的

    注:
    个人感觉这几点不仅仅是设计模式的学习原则,也是一个其他技术的学习准则,有个基本认知,然后知道什么时候使用,如何使用,怎么用,何时不该用,是怎么设计出来的?

但愿如此图所言
3.在该书中介绍了OO原则,不可以轻视,OO原则是设计两难的时候做出判断的标准。OO原则是我们的目标,而设计模式是我们的做法。
4.当涉及“ 维护”时,为了“复用”(reuse)目的 而 使 用 继 承 ,结局并不完美。这里书中举得例子是Duck鸭子的例子,有swim(),quack(),display(),添加新功能fly,在超类Duck上添加fly方法,结果是全部鸭子都会飞,却没注意到橡皮鸭也会飞了。有人想到可以把fly方法覆盖掉,变成什么也不做。如果再添加一个诱饵鸭(木鸭),那么要把quack()和fly()都覆盖掉,变成什么也不做。

那么可知,利用继承可能会造成很多问题,比如:
a. 代码在多个子类中重复
b. 运行时的行为不容易改变
c. 很难知道所有鸭子的全部行为
d. 改变会牵一发动全身,造成其他鸭子不想要的改变

5.改成利用接口实现呢?
这里写图片描述
这真是一个超笨的主意,你没发现这么一来重复的代码会变多吗?如果你认为覆盖几个方法就算是差劲,那么对于48个Duck的子类都要稍微修改一下飞行的行为,你又怎么说?!
那该如何去做呢?

我们会用老方法找出一个解决之道:“采用良好的OO软件设计原则”。
6.软件开发的一个不变真理:不管当初软件设计得多好,一段时间之后,总是需要成长与改变,否则软件就会“死亡”。
这里写图片描述等各种各样的情况
7.上述中提及的解决之道,OO软件设计原则之一:
这里写图片描述
把 会 变 化 的 部 分 取 出并“封装”起来,好让其他部分不会受到影响。

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

换句话说,如果每次新的需求一来,都会使某方面的代码发生变化,那么你就可以确定,这部分的代码需要被抽出来,和其他稳定的代码有所区分。

下面是这个原则的另一种思考方式:“把会变化的部分取出并封装起来,以便以后可以轻易地改动或扩充此部分,而不影响不需要变化的其他部分”。

几乎是每个设计模式背后的精神所在。所有的模式都提供了一套方法让“系统中的某部分改变不会影响其他部分”。

下面还是以鸭子为例,进行分离
从哪里开始呢?就我们目前所知,除了fly()和quack()的问题之外,Duck类还算一切正常,似乎没有特别需要经常变化或修改的地方。
现在,为了要分开“变化和不会变化的部分”,我们准备建立两组类(完全远离Duck类),一个是“fly”相关的,一个是“quack”相关的,每一组类将实现各自的动作。
我们知道Duck类内的fly()和quack()会随着鸭子的不同而改变。
为了要把这两个行为从Duck类中分开,我们将把它们 从Duck类
中取出 来,建立一组新类来代表每个行为。
这里写图片描述
8.设计鸭子的行为
如何设计那组实现飞行和呱呱叫的行为的类呢?
我们希望一切能有弹性,毕竟,正是因为一开始鸭子行为没有弹性,才让我们走上现在这条路。我们还想能够“指定”行为到鸭子的实例 。 比方说, 我们 想要产生一个新的 绿头鸭实例,并指定特定“类型”的飞行行为给它。干脆顺便让鸭子的行为可以动态地改变好了。换句话说,我们应该在鸭子类中包含设定行为的方法, 这样就可以在“运行时”动态地“改变”绿头鸭的飞行行为。
下面引入第二设计原则,这里写图片描述
从现在开始,鸭子的行为将被放在分开的类中,此类专门提供某行为 接口 的实现。
这样,鸭子类就不再需要知道行为的实现细节。
我们利用接口代表每个行为,比方说,FlyBehavior与QuackBehavior,而行为的每个实现都将实现其中的一个接口 。

注:这样的做法迥异于以往,以前的做法是:行为 来自 Duck超类的具体实现,或是继承某个接口并由子类自行实现而来。这两种做法都是依赖于“实现”,我们被实现绑得死死的,没办法更改行为(除非写更多代码)。

Bulala~(我女朋友经常用的,我也在这用一下了,哈哈)
再注:
我不懂你为什么非 要 把FlyBehavior设计成接口 。 为何不使用抽象超类,这样不就可以使用多态了吗?
答:这个问题在没看这本书之前也经常想,但是不明白,现在就有一种恍然大悟的感觉。“针对接口编程”真正的意思是“针对超类型(supertype)编程”,“针对接口编程”,关键就在多态。
“针对超类型编程”这句话,可以更明确地说成“变量的声明类型应该是超类型,通常是一个抽象类或者是一个接口,如此,只要是具体实现此超类型的类所产生的对象,都可以指定给这个变量。 这也意味着,声明类时不用理会以后执行时的真正对象类型!”

如果你这里不是非常清楚的理解,那么可能是多态理解的不到位,那么再来看下多态:
假设有一个抽象类Animal,有两个具体的实现(Dog与Cat) 继承Animal。
做法如下:
“针对实现编程”

    Dog d = new Dog( );    d.bark( );

声 明 变 量 “ d ” 为 D o g 类 型 ( 是Animal的具体实现),会造成我们必须针对具体实现编码。
但是,“针对接口/超类型编程” 做法会如下:

Animal animal = new Dog( );animal.makeSound( );

这里写图片描述
我们知道该对象是狗,但是我们现在利用animal进行多态的调用


更棒的是,子类实例化的动作不再需要在代码中硬编码,例如new Dog(),而是“在运行时才指定具体实现的对象”。

a = getAnimal( );a.makeSound( );

我们不知道实际的子类型是“ 什么”……我们只关心它知道如何正
确地进行makeSound() 的动作就够了。
9.实现鸭子的行为
这里写图片描述
这里写图片描述

问:使用 我们的新设计,如果你要加上一个火箭动力的飞行动作到SimUDuck 系统中,你该怎么做?
答:建立一个FlyRocketPowered 类,实现FlyBehavior 接口

由此我们也可以看出,我们的demo现在在扩展性方面有了很大的进步。
10.整合鸭子的行为
关键在于,鸭子现在会将飞行和呱呱叫的动作“委托”(delegate)别人处理,而不是使用定义在Duck类(或子类)内的呱呱叫和飞行方法。

做法如下:
1.首先,在Duck类中“加入两个实例变量” ,分别为“flyBehavior”与“quackBehavior”,声明为接口类型(而不是具体类实现类型),每个鸭子对象都会动态地设置这些变量以 在运行时引用正确的行为类型(例如:FlyWithWings、Squeak等)。
我们也必须将Duck类与其所有子类中的fly()与quack() 删除,因为这些行为已经被搬到FlyBehavior与QuackBehavior类中了。
我们用 两个相似的方法performFly()和performQuack()取代Duck类中的fly()与quack()。稍后你就会知道为什么。
这里写图片描述
2.现在,我们来实现performQuack():

public class Duck {    QuackBehavior quackBehavior;    //每只鸭子都会引用实现QuackBehavior接口的对象。    // 还有更多    public void performQuack() {        quackBehavior.quack();        //鸭子对象不亲自处理呱呱叫行为,而是委托给quackBehavior引用的对象。    }}

从这里的代码,我们可以看出,现在已经基本完成了分离的操作,也就是设计原则的第一个。

未完待续。。。。

1 0
原创粉丝点击