模式概念
设计模式帮助你从其他人而非自己的失败中获取成功的经验。-------Mark Johnson
或许,迈向OOD领域最重要的一步是设计模式的相关活动,在此基础上出现了GOF《设计模式》3,此书列举出了针对不同问题的23种解决方案的设计模式,并用相应的例子来解读每种设计模式的基本概念,这样做能够激起你阅读Gamma所著《设计模式》的胃口,该书现在几乎成为面向对象编程程序员人手必备的“词汇表”。
本书后面的章节列举一个设计演化过程的例子,从方案的最初,通过逻辑和方案演化的过程,得出更为恰当的设计方案。这个例子(模仿废品分类)可以作为一个你自己的prototype不断演化,在此基础上抽提出能够灵活解决这一类问题的方案。
起初,你可以把模式看成解决某一类特定问题的特别聪明和深刻的方法。好比是,好多人可以从不同的角度解决一个问题,然后总结出一个更一般和灵活的解决方案。这个问题也许是你曾经碰到过解决过,但是你的方案也许没有你将在一个模式中所看到的完美。
尽管他们被称作设计模式,他们并不是仅限乎于设计。一个模式看起来似乎与传统的分析、设计、实现毫无瓜葛,实际上,模式涵盖了程序设计中的一整套思想,有时他们会表现在分析层面,或者更高一个层次的设计层面上。这是有趣的,因为一个模式你可以在编码时直接实现,并且你也许并不期望在低层次的设计和实现前来使用。(事实上,你只有到达那些的阶段时,你才能够会使用一种特定的模式)
模式的基本概念也能被看作程序设计的基本概念:加入一个抽象层。无论什么时候,当你对事物进行抽象的时候,也同时是在分离特定的细节,这样做的一个最强有力的动机就是从保持不变的东西分离变化的东西。换句话说,一旦发现因为某种原因,你的部分程序要改变,你要阻止这种变化影响你的整个程序编码。这样做的目的是,不仅能够使你的编码成本更便宜些,而且通常使你的编码易于理解。
通常,开发一个优雅和保持低成本的设计,最困难的部分在于我所称之为的“变化度”,这意味着最重要的东西在于找出系统的变化,或者,换句话说,找到系统最高成本之所在。一旦你找到了“变化度”,你就找到了设计的焦点,围绕它来进行设计。
因此,设计模式的目标是分离代码中的变化部分,如果你以这种方式来看待的话,你会发现一些设计模式早已出现在本书中了。例如,继承(inheritance)可以被看作一种设计模式(虽然是编译器的一种实现),它可以表示所有有同样接口(不变)的对象不同的行为(变化)。组合(Composition)也可以被看作一种模式,因此它可以允许你动态的或静态的改变实现类的对象,这也正是类工作的方式。
你也许早就看到过《设计模式》一书中的另一种模式:迭代器(the iterator,在java 1.0和java 1.1中被任意的称为枚举器(Enumeration),java 2 的容器中称做“迭代器”)。当你通过一个接一个方式遍历或选择集合中的元素时,这种模式隐藏了容器的特定实现。迭代器允许你撰写通用代码对一个序列的对所有的元素执行操作,而不必考虑这个序列的内部实现,这样这个通用代码能够用于任何产生迭代器的容器。
模式分类法(Pattern taxonomy)
随着设计模式的兴起,人们开始滥用模式这个术语,把所有认为好的东西都看作模式。深思熟虑后,我总结出一种层次来描述分类:
1、 编写特定语言的编码作特定类型的事。比如用C编写遍历数组的代码。
2、 特定设计(Design),我们总结出解决特定问题的方案,这也许是一个聪明的方案,但是不能解决通用问题。
3、 通用设计(Design),解决此类问题的通用方案。更一般化的设计,遍布着软件复用。
4、 模式(Pattern),解决一整类相似问题。这通常是在一个标准设计多次应用后,通过这些应用总结出的一个共同的模式。
我觉得这种划分方式有助于显示适用的地方,这并不意味着一种就比另外一种好,也并不意味着把每种解决问题的方案总结成一种设计模式就是好的,这样做只是浪费你的时间,你不可能通过这种方式来发现模式,它通常是随着时间的逝去,不经意间产生的。
在这种分类层次上,还有一种争论---Analysis Pattern and Architectural Pattern
设计结构(Design Structures)
我曾在设计模式上做的一个努力就是他们的分类方法。我经常发现GOF的模式显得晦涩,并不是一直非常有帮助。的确,创建模式(Creational patterns)相当直观:你将会怎样去创建你的对象呢?这是你通常需要问的一个问题,这个命名会直接引领你到那一组模式中去。不过,我发现结构的(Structural)和行为的(Behavioral)很少有能用得上的区别,对待一个问题时,我还不能够清晰地说:“这里你需要一个结构型的模式”,所以那种分类并不能给我一个方案。(我很乐意承认这里我缺少了一些东西)
这个问题让我步履蹒跚,首先一些GOF模式的底层结构并不相似,并且在这种相似性上挖掘一些关系。然而这是一个有趣的实验,我认为最终这不会产生很多有用的东西,因为关键在于去解决问题。因此,用处在于你要解决的问题身上并且试图找到问题和潜在方案之间的关系。
最终,我开始尝试收集基本的设计结构,并且试图辨别是否存在一种方式把遍布于系统的各种设计模式的结构关联起来。目前,我试图整理一份列表,但是最终我希望能确定这些模式之间结构的关系(或许我会尝试不同的汇总方式----现在仍然在成型阶段)。
这里[1]是已有的候选列表,只会从他们中的一些筛选到最终列表里面去。随意的建议别人,或者模式之间的可能关系。
Ø 封装(Encapsulation):一个自我包含和表达的用法模型。
Ø 聚集(Gathering)
Ø 局部化(Localization)
Ø 分离(Separation)
Ø 隐藏(Hiding)
Ø 监护(Guarding)
Ø 连接器(connector)
Ø 边界(Barrier/fence)
Ø 行为变化(Variation in behavior)
Ø 通知(Notification)
Ø 事务(Transaction)
Ø 镜像(Mirror):“the ability to keep a parallel universe(s) in step with the golden world”
Ø 遮蔽(Shadow):“再不同的媒介中做不同的事(也许是代理前面不同的变化)”
设计原则(Design principles)
当我在我的时事通讯[2]中发布我的关于思想的呼唤后,收到了大量的有用的建议,但是跟上面的分类不同的是,我意识到一系列的设计原则与设计结构是同样的重要,不过基于不同的原因:关于你提议的设计你能够提出一些问题,并且进行质量测试。
最少惊异原则(Principle of least astonishment),不要对这个原则感到奇怪
Ø 使一般的事情容易化,少见的事情可能化(Make common things easy, and rare things possible)
Ø 得墨琴法则(Law of Demeter),不要和陌生人说话,一个对象最好只引用他自身,它的属性,和他方法中的参数。
Ø 减法原则(Subtraction),当一个设计完成时,你不能从中删减任何东西
Ø 在一般化之前先简化(Simplicity before generality[3]):奥克姆剃刀法则,最简单的东西是最好的。在框架中我们通常会发现一个问题,设计通常被用来一般化的问题而无视于实际系统。这会导致一大堆令人眼花缭乱的选项,它们经常不实用,被误用或者根本毫无用处。然而,大多数特定系统开发者的工作,问题一般化并不是总是切合实际。一般化的最好途径是通过很好定义的具体范例。因此,这个原则是简单设计和通用设计间的纽带。当然,简单设计也完全可能是更一般化的设计。
Ø 自反性(Reflexivity),每个类一个抽象,每个抽象一个类;这个原则也可以被称为同质(Isomorphism)。
Ø 独立性或者正交性(Independence or Orthogonality),单独表达独立的思想,这补充了分离(separation)、封装(encapsulation)和变化(varation),是高内聚低耦合的部分。
Ø 一次而且只能一次(Once and once only),当重复是次要的,并且两段代码基于同样的原因表达同样的目的时,避免逻辑和结构的重复。
当进行这个思想头脑风暴的过程时,我希望提出一小部分的基本原则能够被你的头脑所领会,当你分析一个问题的时候。然而,当你分析你的设计的时候,你也可以把上面的其他原则作为一个参照。
模式分类(Classifying patterns)
GOF提出了23种不同的设计模式,依据三个目的来分类的(这些目的是围绕他们变化的特定方面)。这三种分类是:
1. 创建型( Creational):一个对象怎样被创建?这经常包括分离创建对象的细节,因此你的代码不是依赖于对象的类型并且你不必改变当你添加一个新类型的对象时。上述的singleTon模式被分类为创建型模式,在这本书的后面,你将会看到工厂模式(Factory)和原型模式(protoType)。
2. 结构型(Structural):设计对象满足特定的项目约束。这种方式下的工作,确保和其他对象关联的对象不会因为系统的改变而改变他们的关系。
3. 行为型(Behavioral):在一个程序中控制特定类型操作的对象。这个封装你想要执行的过程,比如解释一种语言,满足一个请求,遍历一个序列(比如迭代器中遍历),或者实现一个算法,本书包括了观察者模式(Observer)和参观者模式( Visitior)的例子。
《设计模式》一书中对这23种设计模式都有一个或多个例子进行说明,是用C++或者smalltalk 来描述的(这没什么大不了的,你很容易用java转化这些概念。)本书将会按照自己的思路研究学习设计模式。本书将会通过一些例子令你对什么是设计模式,为什么他们是重要的有一个直接的感观。
多年来的接触,我逐渐意识到模式本身使用了一些基本的组织原则,并非设计模式一书中描述的那么复杂。这些原则基于实现的结构,在这之中我看到了模式之间极大的相似性。尽管我们避免实现接口,我还是经常发现它适宜于思考,特别是易于去领会,在结构化原则术语下的模式。本书将尝试从基于结构的角度解析设计模式,而非《设计模式》一书中的分类法则角度。
开发面临的挑战(The development challenge)
开发组织、UML过程、极限编程
价值评估、能力成熟度模型
Wiki Page: http://c2.com/cgi-bin/wiki?CapabilityImMaturityModelArticle: http://www.embedded.com/98/9807br.htm
成对编程研究
http://collaboration.csc.ncsu.edu/laurie/
单元测试
在此书的一个早期版本中,我就确定了单元测试的重要性(贯穿我所有的书籍),并且当时JUnit 是很冗长和沉闷的以至于无法思量。那时,我用java的反射机制自己写了一个单元测试的框架,简化必要的语法来完成单元测试。《java编程思想》的第三版中,我开发了另一个单元测试框架为这本书来测试例子的输出。同时Junit也发生了一些变化,添加了一些十分相似的语法,到我在这本书早期的一个版本曾经用过的,我不知道我对这些变化有多大的影响,但是仅仅因为这个发生了我就很高兴,因为我感觉不必去支持我自己的系统了(你依然可以找到一些有关的URL),并且能够简单的推荐这些事实上的标准。我曾经介绍和描述过Junit编码的风格,我认为它是一个最好的实践(主要因为简单),在《java编程思想》第三版,第十五章。关系到这本书,在那个章节我对你将看到得和本书有关的任何单元测试提供了充分的介绍(不过,单元测试的代码并不包含在本书的文本格式中)。当你为本书下载这些代码时,单元测试是和这些代码在一起的。
测试代码的位置
(From Bill)
公开的: test 子目录; 另外的包(不是在jar包里面).
包访问: 同样的包, 类代码下面的子目录 (不是在jar包里面)
私有访问: (白盒测试).嵌套类,剥离,Junit addons。
3 注意:这些例子为C++编写
[1] 这份列表是由Kevlin Henney, David Scott, and others整理的
[2] 自由的邮箱通告,订阅参见www.BruceEckel.com
[3] 来自于Kevlin Henney的一封邮件
omencathay译
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/25966/viewspace-53310/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/25966/viewspace-53310/
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/bian-cheng-ji-chu/104187.html