第一图书网

物件導向設計模式

Erich Gamma,Richard Helm,Ralph Johnson,John Vlissides 培生
出版时间:

2001  

出版社:

培生  

作者:

Erich Gamma,Richard Helm,Ralph Johnson,John Vlissides  

译者:

葉秉哲  

Tag标签:

无  


图书封面

图书标签Tags

广告

下载页面


物件導向設計模式 PDF格式下载



  没看过的一定要看,不管你用什么语言。
  
  已看过的一定要再看,不管是什么时候。
  
  经典的经典。
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  


  这应该算是学术著作——从最后一章写道的编著历史看,也确实如此(最先起源于Erich的博士论文)。恐怕大部分读者都会对这样的书籍感到枯燥。不过倒挺适合我的口味:-D。由于写作年代久远等缘故,书中的23种设计模式都是“古典”设计模式了。从现在的角度看,这些都只是设计模式中的冰山一角。书中所举的应用例子也都是很传统的软件应用。不过读下来,感觉多态、复用的思想贯穿全书,基本上每种设计模式都对应着一种要复用的东西(可能需要第二次阅读以确认),这也符合本书的副标题。这个思想应该对当今大多数设计模式仍然适用。


  适合反复阅读。下面的话都出现在这本书中,第一次看时对这些都无感,甚至没有印象。再看时,一眼就发现了这些话
  
  继承与模板注重代码复用
  接口则强调一个对象是否可以被另一个对象替代
  
  面向接口编程
  尽量使用对象组合而不是继承
  。。。。。。
  
  


  这本书的确很好,但是完全搞明白其中的模式并不是很容易。很重要的一点:设计模式只是一个思路,一个方法,最重要的是实现代码复用、代码的可维护性、可读性。抱歉,你的评论太短了抱歉,你的评论太短了抱歉,你的评论太短了抱歉,你的评论太短了抱歉,你的评论太短了


  以前曾看过此书的一部分,感觉就是看不明白或者以为自己看明白了却不知道怎么用。工作半年后,偶然间拿起这本书再看,觉得他说的就是我想要的,软件模块如何复用,类之间怎样组合才有灵活性,不同的目的选用不同的设计模式,设计模式的适用场景,如何协作。这些收获当然与一段时间的工作经验和对工作的思考分不开,我不是那种不做事,想一想就能明白的人。GoF用简单的语言解答的很好,本书原版没有看过,只看了中文的,翻译水平可以认可。此书是看过《程序员修炼之道》之后的必读之物。


  铜弹
  
   二十五年前,弗瑞德.布鲁克斯“没有银弹”的论文让古老的迷信成为了现代软件工程领域家喻户晓的时髦比喻。八年之后,《人月神话》二十周年纪念版发行,他谈了对面向对象编程的看法。面向对象仍然是从次要复杂性(外在技术的复杂)去解决复用的问题,还没有从软件项目针对解决的问题本身的主要复杂性(内在业务逻辑的复杂)上去解决问题,当然,面向对象仍然是一颗有助于代码和算法级别复用的铜弹。
   人们似乎永远找不到银弹,因为之所以需要雇佣程序员,就是我们要解决问题。如果问题的业务逻辑本身就是复杂和全新的,就不太可能存在重用的万能方法来提高效率。
  
  四人帮
  
   但是我们仍然可以从相似问题的成功解决方案中归纳经验,设计模式的概念就是从实际设计问题的解决中涌现的。绰号四人帮(gang of four)用来戏称《设计模式:可复用面向对象软件的基础》一书的四位作者,同时方便将他们最初的圣经和其它的关于设计模式的书区别开来。《设计模式》一共总结出了23种成功的设计思路,按不同的标准进行了分类,以便比较、启发我们提出新的模式。设计模式的概念标志着开始有更多关注在主要问题的解决上而不仅仅停留在技术问题上。
   模式依据目的可分为创建型、结构型和行为型三种。创建型模式与对象的创建有关,结构型模式处理类和对象的组合,行为型模式对类或对象怎样交互和分配职责,通常涉及类方法。我将模式按照相关的主题进行分组,综合上述两种分法,可以得到一个如下的表格:
  
  
   | 创建型 | 结构型 |行为型
  组合 | Abstract Factory |Bridge |Visitor
  
  层次 | | Composite |Interpreter
   | | |Iterator
   | | |Chain of Responsibility
  
  集中 | Singleton | Flyweight | Mediator
   | |Facade | Command
   | | |Observer
  
  解耦 |Factory Method | Decorator | State
   | Prototype |Proxy |Strategy
   | Builder |Adapter |Template Method
  
  序列化 | | | Memento
  
  组合爆炸
  
   在设计模式时,第一个要考虑的问题是类的组合爆炸问题。当一个抽象有多个具体实现时,通常用继承来协调。但是,如果问题包含有多个层次的抽象,机械的使用单一的继承策略来对应所有的组合会产生大量难以维护的类。为了让代码易于修改扩充,应该将不同的抽象部分分离开来,分别继承,然后通过对象间的引用来组合。例如,在抽象工厂模式中,有两个方面的抽象问题,一个是工厂的抽象问题,不同的工厂在不同的情况下会采用不同的具体标准构造产品类,另一方面有产品类的抽象问题,不同的一系列产品需要一个产品抽象类来统一他们的构造、使用接口。整体上,每一个具体的工厂都会引用每一个不同的具体产品对象。在结构型模式中,桥接模式也通过分离两个不同的抽象来实现,两个抽象通过基类的公共接口间的桥接整合在一起。行为型模式中的访问者模式解决这样一个双分派问题:对于一个具体的方法,不仅跟接受访问的对象类型有关,还和访问者的类型有关。这些模式最终产生一个拓扑结构像矩形的二维组合,每个组合都对应一种具体的完整实现。
  
  层级
  
   设计类的层级结构应该尽量简单。树形拓扑结构是一种常用的数据结构,适用于复杂问题的分而治之。静态的继承来对应对象间的动态的树形关系并不灵活。组合模式将代表叶节点的类和容器的类继承于共同的构件类,统一两者的接口,容器类返过来引用其基类构件类。对象通过递归组合,灵活的构成一个树形的拓扑结构。运用对象间的引用而不是类的继承,可以减少所设计类的层次,同时增加灵活性。职责链模式将对象引用连成一条链,请求被依次传递,直到有某个对象的方法处理为止。对于层次复杂的聚合结构,使用迭代器模式能提供按一定顺序访问元素的方法,解耦程序的复杂性。另一与复杂层次有关联的模式是解释器模式,它用于定义并执行一个文法的解释。由于文法通常可以由较短的BNF表示且结构较为固定,因此,解释器的递归组合可以直接用继承来对应。
  
  集中
  
   某些模式体现出集中抽象的特点。在创建型模式中,单件模式可以保证类在实例化后只有一个全局集中的访问点。在结构型模式中,享元模式中少量类的享元对象被反复引用,大量的引用者集中于一个享元,外观模式则将子系统的一组接口集中于一个高层接口,使得这一子系统更加易于使用。在行为型模式中,多个对象之间的行动协调往往有一个指挥中枢,命令模式的中枢是命令类,观察者模式则是被观察类,中介者模式则是中介者。这些模式都是单分派机制的实现:对于一个具体的方法,只跟一个对象的类型有关。在中介者模式和命令模式中,具体方法由发送请求的对象类型决定,而观察者模式,则是由接受请求对象的类型决定。
  
  接口编程
  
   好的面向对象编程应当对接口编程,而不是对实现编程,这样做使得客户无须知道使用对象的类型或实现,只需用抽象类中定义的已知接口操纵对象,这将极大地减少子系统实现之间的相互依赖。构建型模式中的原型模式可以无须知道所创建对象类型,构建者模式利用接口指导复杂对象的构建,无须知道创建对象的具体实现,工厂模式定义一个创建对象的接口,将一个类的实例化延迟至子类。在结构型模式中,代理模式和装饰模式都将一部分的功能分离,委托内部实际实现或由外部的装饰器一步步的增加功能。适配器模式则将一个类的接口转换成客户希望的另一个接口,这对于复用已有的代码十分有用。在行为型模式中,模板方法模式定义一个操作中的算法的骨架,将一些步骤延迟到子类,方便修改算法的某个特定步骤。因此,它使用的是钩子操作,父类方法空缺,由子类实现,而不是抽象操作,子类调用父类的方法。策略模式和状态模式收集所需的全部上下文,然后通过基类接口,委托具体的策略类或状态类来实现实际的功能,用户可以方便的替换策略或状态的实现。
   观察者模式其实是一种回调机制,而备忘录模式现在常常被称为序列化。
  
  语言无关
  
   设计模式是从“设计思路”的角度研究编程,理论上是和语言无关的,但是实践中由于设计模式是从具体的案例总结而来的,因此在成文过程中不可避免的与特定的语言相关联。由于C++、Java,设计模式通常是在上述的语境下所讨论的。如果从今天的角度看,有些设计模式,与其说是发挥语言的特点,倒不如说是在克服语言设计本身的不足。多年来计算机硬件飞速发展,动态语言逐渐流行。动态语言的特性,使得不少设计模式得到许多精简。
  
  动态语言:一等公民
  
   在动态语言中,类型是一等公民,不需要再通过继承抽象类的方式预留公共接口,而且类的构建也是动态的,很多情况下不需要设计工厂类来构建,所以抽象工厂模式、享元模式、工厂方法、状态模式和指责链条模式这六种模式可以简化甚至不需要设计。同样,函数在动态语言中也是一等公民,命令模式实现更容易,另外策略模式、模板方法模式、访问者模式这四种模式都能简化。
  
  广义函数机制
  
   Lisp这种动态语言的对象系统,即CLOS标准不是基于消息机制,而是基于广义函数机制。定义一个抽象的广义函数后,通过特化滚广义函数类型参数来定义一个具体的方法。这意味着方法不是属于类,而是实际上属于广义函数。更关键的是,广义函数的参数数量没有限制,本质上是一种多分派机制,不仅不需要设计访问者模式来支持双分派,而且可以实现任意多的分派。多分派特性又被称为多重方法。构建者模式完全可以用多重方法来实现,因为构建函数的具体方法不仅与读入标记对象的内容有关,也和标记对象的类型,被构建对象的类型有关。
  
  方法组合
  
   当广义函数特化被调用时,它会自动将符合特化条件的方法收集起来,并且按照最特定的匹配优先或者指定的顺序来执行。这种特点提供了一种叫做标准方法组合的技巧。中介者模式、观察者模式这样本质上单分派的机制,可以用方法组合代替,比如在主方法的请求执行后,用after:的辅助方法响应执行。
  
  宏与元编程
  
   Lisp的宏定义具有“元编程”的特点。它可以在普通代码运行前的宏时间预先处理代码。这为编程语言提供了语法上的抽象,可以直接设计BNF范式对应的宏来代替解释器模式。Lisp正因为这个特点所以有众多方言。Mathematica没有宏,但是可以通过Hold和Release操作在代码运行之前,对其进行操作,或者用ToString/ToExpression的组合,将代码转化成字符串,用正则表达式处理之后在转化回表达式运算,可以代替宏的功能,实现元编程。
   动态语言往往有模块机制,这样我们可以建立统一的接口却不再需要设计外观模式,不需要要生成对象。
  
  多范式编程
  
   动态语言除了传统的指令式、递归式的编程范式外,还支持其它多范式编程。Mathematica支持函数式编程,基于lambda演算的函数式编程具有无副作用的特点。符号和方括号的组合可以看成是面向对象编程的部分支持。不过,Mathematica并不需要传统意义上的面向对象系统,因为动态语言不需要继承一个公共的接口,一切都是动态加载的,方法和符号的关系可以用“广义函数”的角度来看待。
  
  逻辑编程
  
   Mathematic支持逻辑编程,即基于规则的编程。在Mathematica中,每一个:=语句都会对符号对象生成对应的:->匹配规则,可以简单的利用Mathematica内置的许多数学规则进行:=语句定义,也可以直接对符号联系的所有:->匹配规则进行修改,自定义的方式来进行。
  


   曾经听人说过,看不懂一本书,不是由于书写的不好,而是你无法领悟其中讲述的内涵。只有你经历过与作者类似的经历,才能明白作者所说。
   《设计模式》自从面世而来,经过多次再版,经久不衰。有人觉得内容很抽象,无法理解。三年前,我第一次接触设计模式时,同样对里面的实例和定义一头雾水。现在,翻起这本书,其中的23种模式,都能在做过的项目中找到踪影。
   这本书并不适合多年前的我,却适合现在的我。


相关图书