本文摘选自已故知名软件大师John Vlissides的Pattern Hatching (Design Patterns Applied)【中译本名为:《设计模式沉思录》,葛子昂译,人民邮电出版社】一书。该书出版于1998年,但中译本一直到2010年才出版,?!。在本文中,Vlissides针对普遍存在的对模式的一些误解进行了诠释,以便我们可以更加深入地理解和掌握模式。Sunny转载本文时在文中增加了一些Vlissides的照片,以此缅怀这位令人尊敬的模式先驱!
--------------------------------------------------------------------------------------------------------------------------
这些日子,模式引起了大家强烈的兴趣,同时还伴随着一些迷惑、诧异和误解。这在一定程度上体现了主流软件开发人员认为这个领域有多么新,虽然从严格意义上说,它并不是一个新领域。这个领域的快速发展,也造成了一些空白。作为模式的倡导者,我们对此负有一定的责任:我们虽然一直努力让大家理解和接受模式,但是工作并不彻底。
为此,我感觉自己有义务来纠正那些对模式比较明显的误解,这些误解我常常耳闻,甚至可以自成模式了。我甚至还开玩笑地采用模式的形式来表述它们……直到那一刻我幡然醒悟:将任何事物都归纳为模式,这种行为本身就是对模式的一种误解!无论如何,请记住我并不是代表模式社区在发言。虽然我认为大多数模式专家都会同意这些是对模式最常见的误解,但就如何消除这些误解而言,他们的意见可能会与我的相左。
这些年人们对模式众说纷纭,令我反复思考,众多误解不过分为三类:一类有关模式是什么,一类有关模式能够做什么,还有一类有关一直以来在推动模式的社区。我所列举的"十大"误解都可以被归到这三类中。因此,我会将它们分门别类。首先来看看关于模式是什么的误解。
"模式就是在一种场合下对某个问题的一个解决方案。"
这是Christopher Alexander的定义,因此把它算作一种误解可能会显得有些离经叛道。但下面这个反例应该能够显露出它的不足。
问题:如何在过期之前兑现中的彩票?
场合:离最后期限只有一小时,一条狗把彩票吃了。
解决方案:剖开狗的肚子,取出彩票,然后飞奔到最近的兑现点。
虽然这是在一种场合下对一个问题的解决方案,但它并不是一个模式。那它缺少了什么呢?至少需要三样东西。
(1) 再现(recurrence),这使得该解决方案不仅与当前场合下的问题有关,而且与当前场合之外的问题也有关。
(2) 教学(teaching),这将教会我们去理解怎样对解决方案加以完善,从而适应问题的变体。(对实际使用的模式来说,与教学有关的大部分内容都包含在对问题的描述、对解决方案的描述以及应用模式后得到的结果中。)
(3) 一个用来指代模式的名字。
诚然,一个令所有人都满意的定义是很难找到的,从"pattern-discussion"邮件列表(即[email protected] )中持续的争论可略知一二。其中的困难在于,模式既是事物又是对相似事物的描述。区分两者的一种方法是,统一使用术语模式来表示描述,用模式实例来表示对模式的具体运用。
但是,定义术语可能只是徒劳无功,因为一个定义也许对一部分受众(比如程序员)有用,但对另一部分受众(比如掌管公司财政大权的执行官)来说却毫无意义。当然,我也不会尝试在这里给出一个最终的定义。我只想说,任何一个规定模式的组成要素的定义,除了要讨论问题、解决方案和场合之外,还必须涉及再现、教学以及命名。
误解2
"模式只是行话、规则、编程技巧、数据结构……"
我称这种误解为"不以为然"。诚然,将不熟悉的事物归纳成已知的事物对我们来说是一件很自然的事情,尤其是在我们没有兴趣对不熟悉的事物进行深入研究的时候。再者,用新瓶装旧酒并号称创新的事情我们已经屡见不鲜了。保持警惕是应该的。
然而,"不以为然"并没有经验依据,很多时候它只是基于表面相似性的一种看法,还掺和些许轻视的态度。此外,从来没有什么东西是全新的,其实自从每个人出生起,各种模式就已经存在于他们的脑子里了。新的只是我们开始对模式进行命名并把它们记载下来。
来看看上面这句话。事实上的确存在一些模式行话,比如"模式"(pattern)本身、"推动力"(force)、Alexander的"无名的品质"(quality without a name),等等。但我们很难把模式简单归纳成行话。与计算机科学中的大多数领域相比,模式几乎没有引入什么新术语。事实上这是模式的特征,一个好的模式天生就很容易为它的受众所理解。虽然模式可能会用到它所面向的目标领域的行话,但我们几乎不需要为模式定义专门的术语。
模式不是可以盲目应用的规则(否则有悖于模式的教学特性)。模式也不仅仅是编程技巧,虽说"惯用法"关注的是与特定的编程语言有关的模式。"技巧"在我听起来有些贬义,它过分强调了解决方案,而忽略了问题、场合、教学以及命名。
毫无疑问,一项新事物要被接受会经历三个阶段:第一个阶段,它被当作垃圾,无人问津;然后它好像是不可行,无法推广;最后它变得显而易见,理所当然,人们会说:"我们一直以来都是这么做的。"模式目前还没有完全脱离第一阶段。
误解3
"看到了冰山的一角,就等于看到了冰山的全部。"
以偏盖全不是一种正当的做法,如果用这种方式来看待模式,那就大错特错了。模式所涉及的领域、内容、范畴和风格非常广泛,而且它们的质量也千差万别。只要随便翻阅Pattern Languages of Program Design 丛书中的一本,就可以感受到这一点。模式和编写模式的人一样多样,也许有过之而无不及。随便举几个例子,Alistair Cockburn、Jim Coplien、Neil Harrison以及Ralph Johnson等,虽然这些作者一开始也曾尝试用多种风格来为不同领域编写模式,但是现在他们早已经超越了这个阶段。因此,仅仅通过少数几个例子就对模式下一个笼统的结论是错误的。
误解4
"模式需要工具或方法的支持才能生效。"
在过去的5年中,我曾经编写过模式,使用过模式,并帮助过别人使用模式,也参与设计过至少一个基于模式的工具。我可以很有把握地说,模式的优点来自于对模式本身的应用,也就是说不需要任何形式的支持。
当我在谈论这个话题的时候,我通常会指出模式的4个主要优点。
(1) 它们提炼出专家的经验和智慧,为普通开发人员所用。
(2) 它们的名字组成了一个词汇表,有助于开发人员更好地交流。
(3) 系统的文档若记载了该系统所使用的模式,则有助于人们更快地理解系统。
(4) 它们使得对系统进行改造变得更加容易,无论系统原来的设计是否采用了模式。
长久以来我原本认为大部分的优点来自第1点。现在我认识到第2点的重要性不亚于第1点。想一想:在软件开发的过程中,开发人员之间的口头及电子形式的交流的信息量有多少字节?我猜即使没有几吉字节,也有好几兆字节。(在我们编写《设计模式》一书的过程中,我保存下来的我们4人之间来往的电子邮件文件大小达数兆字节之多。我认为我们所付出的精力,差不多相当于开发一个小型到中等规模的软件项目。)交流如此多耗时自然多,任何有助于提高交流效率的东西都将为我们节省相当可观的时间。因此,模式使人与人之间的交流更顺畅高效。随着软件开发项目的规模变得越来越大,软件的寿命变得越来越长,我对第3点和第4点的重视程度也在不断提高。
简而言之,模式是供大脑消化吸收的食粮,而不是供工具加工的材料。方法论和自动化的支持对模式可能会有好处,但我相信这些都只是锦上添花的东西而已。
我们到目前为止讨论的误解都与模式是什么有关。现在让我们来讨论一些关于模式能做什么的误解。这些误解有两类:夸大其词类和轻描淡写类。
误解5
"模式可以保证可复用的软件、更高的生产率、世界和平,等等。"
这个误解很容易批驳,因为模式并没有保证任何东西。它们甚至不能增加从中获取益处的可能性。模式并不能代替人来完成创造,它们只不过给那些缺乏经验但却具备才能和创造力的人带来了希望。
人们说到好的模式,会有恍然大悟之感。只有当模式能够触动心弦时,这种情况才会发生。如果模式无法触动心弦,那么它就像人迹罕至的森林中的一棵大树,纵使轰然倒下也没有人能听到它的声音。模式也是如此:即便它编写得再好,如果不能引起人们的共鸣,那么它好在哪里呢?
模式只不过是开发人员军火库中的另一件武器。将太多东西都归功于模式只能适得其反。要防止夸大其词的宣扬引发抵触情绪,最好的方法就是--少说多做。
误解6
"模式可以'产生'整体架构。"
这种误解与上一种误解很相似,只不过夸张的程度要轻一些。
在模式的论坛里,定期会有一些关于模式的产生能力(generativity)的讨论。我认为,产生能力指的是模式能够创造新行为(ermergent behavior)的能力。这种表述听起来很酷,其意思是模式能够帮助读者解决模式没有明确解决的一些问题。就我所知,还有一些观点认为,真正的产生能力几乎能够自动实现这一点。
对我来说,产生能力的关键在于模式与教学相关的部分,例如,对问题的描述和对解决方案的描述,或对效果的讨论。在定义和提炼架构的时候,这些见解尤其有用。但模式本身并不能产生任何东西,能够产生东西的是人,只有当人具备足够的经验并且他们使用的模式足够好的时候,他们才能够这样做。而且,模式不可能涵盖架构的方方面面。给我看一个稍有规模的设计,我一定能发现既有模式尚未涉及的许多设计问题。也许这些问题不常见或不经常发生,或者只不过它们尚未被编写成模式的形式。但无论如何,我们需要运用自己的创造力来填补各种现有模式之间的空白地带。
误解7
"模式是用于(面向对象的)设计或实现的。"
误解的另一个极端是过分贬低模式的作用,就像现在讨论的这一种。竟然有人会相信这种说法,坦白地说,我对此感到很惊讶。然而有许多人曾经就这个问题问过我,多到足以让它能够在十大误解中占有一席之地。如果你觉得这种误解太过幼稚,那么可以直接跳到下一种误解。
如果模式不能把专家的经验记录下来,那么它们就一无是处。究竟记录哪些经验则由模式的编写者决定。在面向对象的软件设计中,当然有值得记录的经验,但在非面向对象的设计中,同样有值得记录的经验。不仅在设计领域有值得记录的经验,而且在分析、维护、测试、文档、组织结构等领域都有值得记录的经验。这些不同领域中的模式正在浮现。目前在分析模式领域,已经至少出版了两本书,而且每一届的PLoP会议都会吸引一些新型的模式。(提交给1996年会议的一个模式特别有意思,它是关于音乐作曲的模式!)
与大多数的误解一样,这种误解也有一定的道理。如果看一看人们使用模式的形式,就会发现两种基本的风格:一种是《设计模式》一书所使用的高度结构化的GoF风格,另一种是Christopher Alexander的近乎纯文学的风格--叙述的文体,采用尽可能少的结构。在我涉足为面向对象设计以外的领域编写模式之后,才认识到GoF风格是多么地偏向面向对象领域。在我尝试过的其他领域,GoF风格根本不适用。对C++惯用法来说,它的结构图应该是什么样的?对音乐作曲的模式来说,它在实现上的取舍应该是什么样?对于用来撰写好的说明文的模式来说,它的协作部分应该是什么样?
显然,没有任何一种模式能够适用于所有领域。唯一能够适用于任何领域的是一个通用的概念--无论在什么领域,模式都是一种用来记录和传播专家经验的工具。
误解8
"没有证据表明模式对任何人有帮助。"
这种误解在过去还能站得住脚,但现在已经不是那么回事了。人们正在通过各种渠道报道模式所带来的好处,这些渠道包括Software-Practice and Experience 之类的期刊,以及OOPSLA和ICSE之类的会议。Doug Schmidt也曾经表示过,模式对大学生和研究生的计算机科学教学有诸多好处。虽然这些大多是定性的分析,但就我所知,至少有一个团体正在进行受控的实验,以获取量化的结果。
随着时间的推移,我们会更加清楚使用模式所带来的好处和隐患。即使最初的反馈非常好,我们仍然需要积累更多的经验,这样才能得到一个更加全面的评估。但是,如果仅仅因为模式所带来的好处还没有被完全量化就拒绝马上开始使用模式,那绝对是很愚蠢的行为。
关于模式能够做什么的谬论就到此为止。下面最后两种误解与模式本身无关,而与拥护模式的社区有关。
误解9
"模式社区是一个由精英分子组成的小帮派。"
我很想知道这样的想法从何而来,这是因为如果模式社区确实有哪方面值得一提,那一定是它的多样性。这一点很容易判断,只要看一看PLoP的与会者就可以知道--人们来自世界各地,既有来自大公司也有来自小型创业公司,有分析师、设计师和实现者,有学生和教授,还有大名鼎鼎的作者和新手。而且令我感到惊讶的是,有几个经常参加该会议的与会者竟然不是搞计算机的!模式社区仍然处于不断变动的状态,每年与会者的流动率都相当高。
模式社区里常常有著作发表,但社区中有学术背景的人相对来说却并不多,对此有人可能会感到不解。事实上,PLoP的大多数与会者都是软件行业的从业人员,而且似乎一直以来都是这样。软件模式的早期拥护者们--包括Kent Beck、Peter Coad以及Ward Cunningham--没有一个是来自学术界的。GoF中只有一个(Ralph)来自学术界,而且他是我所见过的最讲究实用性的学者。模式社区的草根本质显然与那些所谓的同种论(homogeneity)和精英论是背道而驰的。
误解10
"模式社区是为自己服务的,甚至是不怀好意的。"
我曾经不止一次听到对模式的责难,说模式的主要用途是作为那些编著模式方面图书的人的收入来源。甚至还有一种说法是模式正朝着一个不可告人的方向发展。
完全是一派胡言!
作为GoF中的一员,我可以非常肯定地说,我们4人和其他任何人一样,对于人们对《设计模式》的反响感到惊讶。毫无疑问,当设计模式在1994年的OOPSLA会议上初次亮相时,我们4人对它所引起的轰动效应完全没有心理准备,读者的大量需求甚至让出版社都感到措手不及。在写书的整个过程中,我们最多的考虑就是尽我们所能来创造一本最高质量的图书。为了深入理解模式的内容,我们已经太忙了,根本无暇考虑销售问题。
当时的情况就是那样。现在模式已经成为了一个重要的术语,因此有些人想利用它来谋取一些私利也在所难免。但是,如果仔细地阅读那些模式领军人物编写的作品,你就会感受到其中共同的宗旨:将来之不易的专家经验、最佳实践,甚至是竞争优势--多年亲身实践所积累的经验硕果--不仅展露出来而且传授给所有后来者。
正是这种要提升所有读者的软件设计能力的热情,激励着每一位真诚而富有成效的模式编写者。缺少任何一项因素,那只能是适得其反,并最终导致对模式的误解。
John Vlissides(1961-2005),GoF成员,斯坦福大学计算机科学博士,原IBM研究员,因患脑瘤于2005年11月24日(感恩节)病故,享年44岁,为纪念他的贡献,ACM SIGPLAN特设立John Vlissides奖。
更多有关John Vlissides的信息参见:http://c2.com/cgi/wiki?JohnVlissides
更多有关《设计模式沉思录》(Pattern Hatching)的信息参见:http://c2.com/cgi/wiki?PatternHatching
代码味道及重构手段
Martin Fowler针对22种代码味道,提出了相应的重构手段。具体而言,如下表所示:
代码味道 |
常用重构手段 |
接口不同的相似类(Alternative Classes with Different Interfaces)【异曲同工的类】 |
● 重命名方法(Rename Method) ● 搬移方法(Move Method) |
注释(Comments)【过多的注释】 |
● 抽取方法(Extract Method) ● 引入断言(Introduce Assertion) |
数据类(Data Class)【纯稚的数据类】 |
● 搬移方法(Move Method) ● 封装字段(Encapsulate Field) ● 封装集合(Encapsulate Collection) |
数据泥团(Data Clump) |
● 抽取类(Extract Class) ● 引入参数对象(Introduce Parameter Object) ● 保持对象完整(Preserve Whole Object) |
发散式改变(Divergent Change) |
● 抽取类(Extract Class) |
重复性代码(Duplicated Code) |
● 抽取方法(Extract Method) ● 抽取类(Extract Class) ● 上移方法(Pull Up Method) ● 构建模板方法(Form Template Method) |
依恋情结(Feature Envy) |
● 搬移方法(Move Method) ● 搬移字段(Move Field) ● 抽取方法(Extract Method) |
不当的紧密性(Inappropriate Intimacy)【狎昵关系】 |
● 搬移方法(Move Method) ● 搬移字段(Move Field) ● 将双向关联改为单向(Change Bidirectional Association to Unidirectional) ● 将继承替换成委托(Replace Inheritance with Delegation) ● 隐藏委托(Hide Delegate) |
不完备的库类(Incomplete Library Class) |
● 引入外来方法(Introduce Foreign Method)、 ● 引入本地扩展(Introduce Local Extension) |
过大的类(Large Class) |
● 抽取类(Extract Class) ● 抽取子类(Extract Subclass) ● 抽取接口(Extract Interface) ● 将数据值替换为对象(Replace Data Value with Object) |
懒惰类(Lazy Class)【冗赘类】 |
● 内联类(Inline Class) ● 折叠继承体系(Collapse Hierarchy) |
过长的方法(Long Method) |
● 抽取方法(Extract Method) ● 将临时变量替换为查询(Replace Temp with Query) ● 将方法替换为方法对象(Replace Method with Method Object) ● 分解条件式(Decompose Conditional) |
过长的参数表(Long Parameter List) |
● 将参数替换为方法(Replace Parameter with Method) ● 引入参数对象(Introduce Parameter Object) ● 保持对象完整(Preserve Whole Object) |
消息链(Message Chains)【过渡耦合的消息链】 |
● 隐藏委托(Hide Delegate) |
中间人(Middle Man) |
● 移除中间人(Remove Middle Man) ● 内联方法(Inline Method) ● 将委托替换为继承(Replace Delegation with Inheritance) |
并行继承体系(Parallel Inheritance Hierarchies) |
● 搬移方法(Move Method) ● 搬移字段(Move Field) |
基本类型困扰(Primitive Obsession)【基本类型偏执】 |
● 将数据值替换为对象(Replace Data Value with Object) ● 抽取类(Extract Class) ● 引入参数对象(Introduce Parameter Object) ● 将数组替换为对象(Replace Array with Object) ● 将类型码替换为类(Replace Type Code with Class) ● 将类型码替换为子类(Replace Type Code with Subclasses) ● 将类型码替换为状态/策略(Replace Type Code with State/Strategy) |
拒收的遗赠(Refused Bequest) |
● 将继承替换为委托(Replace Inheritance with Delegation) |
霰弹式修改(Shotgun Surgery) |
● 搬移方法(Move Method) ● 搬移字段(Move Field) ● 内联类(Inline Class) |
过分一般性(Speculative Generality)【夸夸其谈的未来性】 |
● 折叠继承体系(Collapse Hierarchy) ● 内联类(Inline Class) ● 移除参数(Remove Parameter) ● 重命名方法(Rename Method) |
Switch语句(Switch Statements)【Switch惊悚现身】 |
● 将条件式替换为多态(Replace Conditional with Polymorphism) ● 将类型码替换为子类(Replace Type Code with Subclasses) ● 将类型码替换为状态/策略(Replace Type Code with State/Strategy) ● 将参数替换为显式方法(Replace Parameter with Explicit Methods) ● 引入Null对象(Introduce Null Object) |
临时字段(Temporary Field)【令人迷惑的暂时值域】 |
● 抽取类(Extract Class) ● 引入Null对象(Introduce Null Object) |
Martin Fowler在Refactoring: Improving the Design of Existing Code(中译名:《重构——改善既有代码的设计》)一书中与Kent Beck一起总结了22种代码坏味(Bad Smells in Code),因为Sunny这段时间正在做一些与代码味道自动识别与自动重构有关的研究工作,对这些内容进行了重新的深入理解与分析。后续将在博客中转载和原创一些相关的文章,希望对广大从事软件开发的朋友们能够带来些许帮助。你在编程过程中面临哪些代码味道?哪些代码味道你觉得最应该消除?对于消除这些代码味道你有何意见和建议?欢迎大家与我一起交流讨论。
注:本文中,代码坏味道的中文名称源于侯捷和熊节的中译本《重构——改善既有代码的设计》。
类内味道
1、Measured Smells(可度量的味道)
(1) Long Method(过长方法)
A method is too long.(方法太长。)
(2) Large Class(过大类)
A class is trying to do too much, it often shows up as too many instance variables.(一个类试图做太多的事情,通常会出现太多的实例变量。)
(3) Long Parameter List(过长参数列)
A method needs passing too many parameters.(一个方法需要传递太多的参数。)
(4) Comments(过多的注释)
Do not write comments when it is unnecessary. When you feel the need to write a comment, first try to refactor the code so that any comment becomes superfluous.(在非必要的情况下不要写注释。当你觉得需要去写一段注释时,你首先应该尝试去重构代码,这将使任何注释都变得是多余的。)
2、Unneccessary Complexity(不必要的复杂性)
(5) Speculative Generality(夸夸其谈的未来性)
If a machinery was being used, it would be worth it. But if it is not, it is not. The machinery just gets in the way, so get rid of it.(如果一个装置【一个设计或实现方案】会被用到,那就值得去做;如果用不到,就不值得。用不到的装置会成为拦路石,因此需要将它搬移。)
3、Duplication(重复)
(6) Duplicated Code(重复代码)
Same code structure happens in more than one place.(在一个以上的地方发现相似的代码结构。)
(7) Alternative Classes with Different Interfaces(异曲同工的类)
Classes are doing similar things but with different signatures. (不同的类做相同的事情,却拥有不同的签名,主要是指方法签名不同。)
4、Conditional Logic(条件逻辑)
(8) Switch Statements(Switch惊悚现身)
Switch statements often lead to duplication. Most times you see a switch statement which you should consider as polymorphism.(Switch语句通常会导致代码重复。大多数时候,一看到Switch语句你应该考虑使用多态来替换。)
类间味道
1、Data(数据)
(9) Primitive Obsession(基本类型偏执)
Primitive types are overused in software. Small classes should be used in place of primitive types in some situations.(在软件中,基本类型被过度使用。在某些场合下,应该使用一些小的类来代替这些基本类型。)
(10) Data Class(纯稚的数据类)
These are classes that have fields, getting and setting methods for the fields, and nothing else. Such classes are dumb data holders and are almost certainly being manipulated in far too much detail by other classes.(这些类拥有一些字段【成员变量】,并提供了对应的Getter和Setter方法,除此以外一无所有。这些类只是一些不会说话的数据容器, 而且它们必定会被其他类过分琐细地操作。)
(11) Data Clumps(数据泥团)
Some data items together in lots of places: fields in a couple of classes, parameters in many method signatures.(一些数据项同时出现在多个地方:例如一对类中的值域【成员变量】,多个方法签名中的参数等。)
(12) Temporary Field(令人迷惑的暂时值域)
Sometimes you see an object in which an instance variable is set only in certain circumstances. Such code is difficult to understand, because you expect an object to need all of its variables.(有时候你会看到一个对象的实例变量仅为某些特定的场合而设。这样的代码将导致难以理解,因为你期望一个对象需要它所有的变量。)
2、Inheritance(继承)
(13) Refused Bequest(被拒绝的遗赠)
Subclasses get to inherit the methods and data of their parents, but they just use a few of them.(子类继承父类的方法和数据,但是它们只需要使用其中的一部分。)
(14) Inappropriate Intimacy(狎昵关系)
Sometimes classes become far too intimate and spend too much time delving in each others’ private parts.(有时候,类之间的关系变得非常亲密,并且需要花费大量时间来探究彼此之间的私有成分。)
(15) Lazy Class(冗赘类)
Each class you create costs money to maintain and understand. A class that is not doing enough to pay for itself should be eliminated.(你所创建的每个类都需要花钱去维护和理解。一个类如果不值其身价,它就应该消失。)
3、Responsibility(职责)
(16) Feature Envy(依恋情节)
The whole point of objects is that they are a technique to package data with the processes used on that data. A Feature Envy is a method that seems more interested in a class other than the one it actually is in.(对象的全部要点在于它是一种封装数据以及施加于这些数据的处理过程的技术。依恋情节是指一个方法对别的类的兴趣高过它本身所在的类。)
(17) Message Chains(过度耦合的消息链)
You see message chains when a client asks one object for another object, which the client then asks for yet another object, which the client then asks for yet another object, and so on. Navigating in this way means that the client is coupled to the structure of the navigation. Any change to the intermediate relationships causes the client to have to change.(你看到的消息链是这样的:当一个客户端向一个对象请求另一个对象,然后再向后者请求另一个对象,然后再请求另一个对象,如此反复。这种方式的导航意味着客户端将与整个导航结构紧密耦合在一起。一旦对象之间的联系发生任何改变,将导致客户端也不得不做出相应的修改。)
(18) Middle Man(中间转手人)
You look at a class’s interface and find that half the methods are delegating to this other class. It may mean problems.(当你审查一个类的接口时发现其中有一半的方法都委托给了其他类,这也许就意味着存在问题了。)
4、Accommodating Change(协调变化)
(19) Divergent Change(发散式变化)
Divergent change occurs when one class is commonly changed in different ways for different reasons.(如果某个类经常因为不同的原因在不同的方向上发生变化就会产生发散式变化。也就是说,一个类拥有多个引起它发生变化的原因。)
(20) Shotgun Surgery(霰弹式修改)
Shotgun surgery is similar to divergent change but is the opposite. Every time you make a kind of change, you have to make a lot of little changes to a lot of different classes.(霰弹式修改与发散式变化类似,却又存在相反的一面。每次进行某种修改时,你都必须对多个不同的类进行很多对应的小修改。)
(21) Parallel Inheritance Hierarchies(平行继承体系)
Parallel inheritance hierarchies is really a special case of shotgun surgery. In this case, every time you make a subclass of one class, you also have to make a subclass of another. You can recognize this smell because the prefixes of the class names in one hierarchy are the same as the prefixes in another hierarchy.(平行继承体系是霰弹式修改的一个特例。在这种情况下,当你为某个类增加一个子类时,你不得不为另一个类也相应增加一个子类。你也许能够识别到这种味道,因为一个继承体系中类的类名前缀与另一个体系中的类名前缀一样。)
5、Library Classes(库类)
(22) Incomplete Library Class(不完善的程序库类)
Library classes should be used carefully, especially we do not know whether a library is completed.(库类在使用时一定要小心,特别是在我们不知道一个库是否完整时。)