这是新的一章
1
Make it Stick
有些人已经解决你的问题了。在本章,你将学到为何(以及如何)
利用其他开发人员的经验与智慧。他们遭遇过相同的问题,也顺利地解决过这些
问题。本章结束前,我们会看看设计模式的用途与优点,再看一些关键的OO设计
原则,并通过一个实例来了解模式是如何运作。使用模式最好的方式是:“把模
式装进脑子里,然后在你的设计和已有的应用中,寻找何处可以使用它们。”以
往是代码复用,现在是经验复用。
欢迎来到
设计模式世界
1 设计模式入门
我们已经搬到对象村,刚刚开始着
手设计模式……这里每个人都在
使用设计模式。很快我们就会通
过设计模式跻身上流社会。
2 第1章
先从简单的模拟鸭子应用做起
J o e 上 班 的 公 司 做 了 一 套 相 当 成 功 的 模 拟 鸭 子 游 戏 :
SimUDuck。游戏中会出现各种鸭子,一边游泳戏水,一边呱
呱叫。此系统的内部设计使用了标准的OO技术,设计了一个鸭
子超类(Superclass),并让各种鸭子继承此超类。
Duck
quack()
swim()
display()
//
鸭子的 其他 方法
display() {
//
外观是 绿头
}
MallardDuck
display() {
//
外观是 红头
}
RedheadDuck
许 多 其 他 类 型 的 鸭 子 继 承
Duck类。
每 个 鸭 子 子 类
型(subtype)负
责 实 现 自 己 的
display() 行为在
屏幕上显示其外
观。
所有的鸭子都会呱呱
叫(Quack)也会游泳
(Swim),所以由超类
负责处理这部分的实
现代码。
去年,公司的竞争压力加剧。在为期一周的高尔夫假期兼头脑风
暴会议之后,公司主管认为该是创新的时候了,他们需要在“下
周”毛伊岛股东会议上展示一些“真正”让人印象深刻的东西来振
奋人心。
因 为 每 一 种 鸭 子 的
外 观 都 不 同 , 所 以
display()方法是抽象的。
模拟鸭子
设计模式入门
你现在的位置� 3
Joe
我 只 需 要 在 D u c k 类 中 加 上
fly()方法,然后所有鸭子都会继承
fly()。这是我大显身手,展示OO才
华的时候了。
所 有 的 子
类都 会 继
承fly()
Joe加上的
主管们确定,此模拟程序需要会飞的鸭子来将竞争者抛在
后头。当然,在这个时候,Joe的经理拍胸脯告诉主管们,
Joe只需要一个星期就可以搞定。“毕竟,Joe是一个OO程序
员……这有什么困难?”
现在我们得让鸭子能飞
其他的鸭子类型……
Duck
quack()
swim()
display()
y()
//
鸭子的 其他 方法 ……
display() {
//
外观是 绿头
}
MallardDuck
display() {
//
外观是 红头
}
RedheadDuck
我们想要的
4 第1章
他 体 会 到 了 一 件
事 : 当 涉 及 “ 维
护”时,为了“复
用”(reuse)目
的 而 使 用 继 承 ,
结局并不完美。
好吧!我承认设计中有一点小
疏失。但是,他们怎么不干脆把
这当成一种“特色”,其实还挺
有趣的呀……
Joe,我正在股东会议上,
刚刚看了一下展示,有很
多“橡皮鸭子”在屏幕上飞来飞去,
这是你在开玩笑吗?你可能要开始去逛
逛Monster.com(编注:美国最大的求职
网站)了……
Joe忽略了一件事:并非Duck所有的子
类都会飞。Joe在Duck超类中加上新
的行为,会使得某些并不适合该行为
的子类也具有该行为。现在可好了!
SimUDuck程序中有了一个无生命的会
飞的东西。
对代码所做的局部修改,影响层面可
不只是局部(会飞的橡皮鸭)!
怎么回事?
quack()
swim()
display()
y()
//
鸭子的其他 方 法
display() {
//
外观是绿头
}
MallardDuck
display() {
//
外观是红头
}
RedheadDuck
quack() {
//
覆盖成吱吱 叫
}
display() {
//
外观是橡皮 鸭
}
RubberDuck
Duck
橡皮鸭子不会
呱呱叫,所以
把 quack() 的定
义覆盖成“吱吱
叫”(squeak)。
在超类中加上fly(),
就会导致所有的子类
都具备fly(),连那些
不该具备fly()的子类
也无法免除。
但是,可怕的问题发生了……
事情出错了
设计模式入门
你现在的位置� 5
Joe想到继承
我可以把橡皮鸭类中
的fly()方法覆盖掉,就好像
覆盖quack()的做法一样
……
quack() { //
吱吱叫
}
display() { //
橡皮鸭
}
y() {
//
覆盖,变成 什 么事都不 做
}
RubberDuck
q A.
代码 在多个子类中 重复。
q B.
运行 时的行为不容 易改变。
q C.
我们 不能让鸭子跳 舞。
q D.
很难 知道所有鸭子 的全部行为。
q E.
鸭子 不能同时又飞 又叫。
q F.
改变 会牵一发动全 身,造成其他 鸭子不想
要的 改变。
quack() {
//
覆盖,变成 什 么事都不 做
}
display() { //
诱饵鸭
}
y() {
//
覆盖,变成 什 么事都不 做
}
DecoyDuck
这是继承层次中的另一个
类。注意,诱饵鸭既不会飞
也不会叫,可是橡皮鸭不会
飞但会叫。
可 是 , 如 果 以 后 我 加 入 诱
饵鸭(DecoyDuck),又会
如 何 ? 诱 饵 鸭 是 木 头 假 鸭 , 不
会飞也不会叫
……
Sharpen your pencil
利用继承来提供Duck的行为,这会导致下列哪些缺点?(多选)