设计模式:可复用面向对象软件的基础
本书是软件工程领域的里程碑式经典著作,由四位国际公认的面向对象软件领域专家(被称为"GoF四人组")合著。书中结合设计实例从面向对象的设计中精选出23个设计模式,总结了面向对象设计中最有价值的经验,并用简洁可复用的形式表达出来。书中涉及的设计模式只收录了那些在不同系统中多次使用过的成功设计,而非描述新的或未经证实的设计。本书豆瓣评分9.1,是计算机科学丛书中的经典之作,适合大学计算机专业学生、研究生及软件开发人员参考。
本书速读
📖 本书核心内容
《设计模式:可复用面向对象软件的基础》由Erich Gamma、Richard Helm、Ralph Johnson和John Vlissides四位国际公认的面向对象软件领域专家合著,机械工业出版社出版,豆瓣评分高达9.1分。四位作者被业界尊称为"GoF四人组"(Gang of Four),本书是软件工程领域的里程碑式经典著作。
本书结合设计实例从面向对象的设计中精选出23个设计模式,总结了面向对象设计中最有价值的经验,并用简洁可复用的形式表达出来。书中涉及的设计模式并不描述新的或未经证实的设计,只收录了那些在不同系统中多次使用过的成功设计。这些模式分类描述了创建型模式、结构型模式和行为型模式三大类设计模式,为软件开发者提供了一套通用的设计语言和解决方案。
本书的核心价值在于:它将软件设计中反复出现问题的解决方案进行了系统化的归纳和总结,使开发者不必每次都从零开始设计,而是可以直接借鉴前人的成功经验。掌握这23个设计模式,是成为优秀软件工程师的必经之路。
🎯 第一部分:设计模式概述
本部分是全书的导论章节,介绍了设计模式的基本概念、分类和使用方法。
什么是设计模式
设计模式是对软件设计中普遍存在(反复出现)的各种问题,所提出的解决方案。本书开宗明义地指出,设计模式不是全新的发明,而是对已有成功设计的归纳和命名。通过给设计模式命名,开发者之间可以用简洁的方式进行沟通——当有人说"这里用观察者模式"时,所有了解设计模式的开发者都能立即理解其含义。
书中强调了面向对象设计的两个重要原则:针对接口编程,而不是针对实现编程;优先使用对象组合,而不是继承。这两个原则贯穿全书,是理解所有设计模式的基础。
设计模式的分类
本书将23个设计模式分为三大类:
创建型模式(Creational Patterns):关注对象的创建过程,将对象的创建与使用分离。包括5种模式:单例模式、抽象工厂模式、建造者模式、工厂方法模式、原型模式。
结构型模式(Structural Patterns):关注类和对象的组合,形成更大的结构。包括7种模式:适配器模式、桥接模式、组合模式、装饰器模式、外观模式、享元模式、代理模式。
行为型模式(Behavioral Patterns):关注对象之间的通信和责任分配。包括11种模式:职责链模式、命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、策略模式、模板方法模式、访问者模式。
实例研究:设计一个文档编辑器
本书用一个贯穿始终的实例——文档编辑器(Editor)的设计——来演示设计模式的应用。通过这个实例,读者可以看到在文档编辑器的各个设计决策点(如文档结构的表示、用户交互的处理、文本和图形的显示、打印输出的生成等),如何运用不同的设计模式来解决问题。这个实例使抽象的设计模式变得具体可感。
🎯 第二部分:创建型模式
创建型模式关注对象的创建机制,将对象的创建过程封装起来,使系统独立于对象的创建、组合和表示方式。
单例模式(Singleton)
确保一个类只有一个实例,并提供一个全局访问点。适用于需要控制资源访问的场景,如数据库连接池、配置管理器、日志对象等。书中详细讲解了单例模式的实现方法(私有构造函数、静态实例、全局访问接口)以及线程安全问题的处理。
抽象工厂模式(Abstract Factory)
提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。适用于产品族的创建场景,如跨平台UI组件库(Windows风格按钮+Windows风格文本框,或Mac风格按钮+Mac风格文本框)。书中分析了抽象工厂的优缺点:易于交换产品系列,但难以支持新种类的产品。
建造者模式(Builder)
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。适用于对象构建过程复杂、需要分步骤完成的场景,如文档编辑器中复杂文档的生成(同时生成文本版和图形版)。书中强调了建造者模式与抽象工厂模式的区别:建造者模式关注分步骤构建,抽象工厂模式关注产品族的创建。
工厂方法模式(Factory Method)
定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。适用于框架设计中,框架需要创建对象但不知道具体类型的场景。书中通过文档编辑器中的Document、Application等例子,演示了工厂方法在框架设计中的核心作用。
原型模式(Prototype)
用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。适用于需要动态加载类、避免创建产品层次结构的场景。书中讲解了原型模式的关键——实现克隆(Clone)操作,以及浅拷贝和深拷贝的区别。
🎯 第三部分:结构型模式
结构型模式关注如何将类或对象组合成更大的结构,形成新的功能。
适配器模式(Adapter)
将一个类的接口转换成客户希望的另一个接口,使原本因接口不兼容而不能一起工作的类可以一起工作。适用于需要使用现有类但其接口不匹配的场景。书中讲解了类适配器(通过多重继承)和对象适配器(通过组合)两种实现方式,并分析了各自的优缺点。
桥接模式(Bridge)
将抽象部分与它的实现部分分离,使它们都可以独立地变化。适用于需要在抽象和实现之间增加灵活性的场景。书中通过窗口系统(不同窗口系统有不同的实现)和图形绘制(不同形状有不同实现)的例子,演示了桥接模式如何解耦抽象和实现。
组合模式(Composite)
将对象组合成树形结构以表示"部分-整体"的层次结构,使得用户对单个对象和组合对象的使用具有一致性。适用于需要表示树形结构的场景,如文档中的图形元素(单个图形和组合图形)、文件系统中的文件和目录。书中详细讲解了透明组合模式和安全组合模式两种变体。
装饰器模式(Decorator)
动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活。适用于需要在运行时动态添加功能的场景。书中通过文档编辑器中的边框、滚动条、字体等装饰器例子,演示了装饰器模式如何通过组合而非继承来实现功能的灵活扩展。
外观模式(Facade)
为子系统中的一组接口提供一个一致的界面,定义一个高层接口,这个接口使得这一子系统更加容易使用。适用于需要简化复杂子系统接口的场景。书中通过编译器子系统(词法分析器、语法分析器、代码生成器等)的例子,演示了外观模式如何为复杂系统提供一个简洁的入口。
享元模式(Flyweight)
运用共享技术有效地支持大量细粒度的对象。适用于需要创建大量相似对象的场景,如文本编辑器中的字符对象(文档中可能有上万个字符,但只需要几百个不同的字符对象)。书中讲解了享元模式的内蕴状态和外蕴状态的区别,以及如何通过对象池实现共享。
代理模式(Proxy)
为其他对象提供一种代理以控制对这个对象的访问。适用于需要控制对象访问的场景。书中介绍了四种常见的代理:远程代理(为不同地址空间对象提供局部代表)、虚代理(根据需要创建开销大的对象)、保护代理(控制对原始对象的访问权限)、智能引用代理(在访问对象时执行额外操作)。
🎯 第四部分:行为型模式
行为型模式关注对象之间的通信和责任分配,描述对象之间如何交互和协作。
职责链模式(Chain of Responsibility)
使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合。将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。适用于需要多个对象处理同一类型请求的场景,如事件处理系统。
命令模式(Command)
将一个请求封装为一个对象,从而可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。适用于需要抽象请求、支持撤销/重做、宏命令等功能的场景。书中通过菜单命令、宏命令、事务等例子,演示了命令模式的强大能力。
解释器模式(Interpreter)
给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。适用于需要实现简单语言解释器的场景,如正则表达式、SQL解析等。书中讲解了如何将语法规则映射到类,以及如何通过递归下降实现解释。
迭代器模式(Iterator)
提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露该对象的内部表示。适用于需要遍历集合的场景。书中讲解了迭代器的核心接口(First、Next、IsDone、CurrentItem),以及正向迭代器和双向迭代器的区别。
中介者模式(Mediator)
用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。适用于对象之间交互复杂的场景,如GUI界面中各个控件之间的协调(对话框中的复选框、按钮、文本框之间的联动)。
备忘录模式(Memento)
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便以后当需要时能将该对象恢复到原先保存的状态。适用于需要保存和恢复状态的场景,如撤销操作、快照功能等。
观察者模式(Observer)
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。适用于事件处理系统、MVC架构中的模型-视图同步等场景。书中详细讲解了推模型和拉模型两种通知方式,以及主题和观察者的注册/注销机制。
状态模式(State)
允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。适用于对象行为随状态变化的场景,如文档编辑器中的工具状态(选择工具、绘图工具、文字工具之间的切换)。书中讲解了状态模式与策略模式的区别:状态模式的状态切换是内部的,策略模式的策略切换是外部的。
策略模式(Strategy)
定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。适用于需要在运行时选择不同算法的场景,如排序算法的选择、压缩算法的选择等。书中强调了策略模式如何通过组合替代条件语句,使代码更加灵活。
模板方法模式(Template Method)
定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。适用于需要定义算法骨架、允许子类定制部分步骤的场景。书中通过文档编辑器中文档打开操作的例子(打开文件、解析、渲染、保存),演示了模板方法模式如何定义算法骨架。
访问者模式(Visitor)
表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。适用于需要对对象结构中的元素执行多种不同操作的场景。书中讲解了访问者模式的双分派(Double Dispatch)机制,以及其在编译器(对AST节点执行不同类型检查)中的应用。
⭐ 金句摘录
"将系统分解成对象集合。因为要考虑许多因素:封装、粒度、依赖关系、灵活性、性能、演化、复用等等,它们都影响着系统的分解,并且这些因素通常还是互相冲突的。"
"面向对象设计中最有价值的两条原则:针对接口编程,而不是针对实现编程;优先使用对象组合,而不是继承。"
"设计模式并不描述新的或未经证实的设计,只收录了那些在不同系统中多次使用过的成功设计。"
"命名设计模式有助于开发者之间的沟通,使复杂的设计概念可以用简洁的方式表达。"
"设计模式不是银弹,但它们是将设计经验转化为可复用知识的有效方式。"
📚 阅读建议
本书适合以下读者群体:
- 有1-3年开发经验的程序员:建议按顺序通读全书,重点理解每个模式的意图、结构、适用性和效果,配合书中的实例研究深入理解
- 有丰富开发经验的高级工程师:建议将本书作为参考书,在实际项目中遇到问题时查阅相关模式,体会"用过不成功的开发经历后再读本书"的感悟
- 计算机专业学生:建议作为课外必读经典,重点学习前6章的导论内容和创建型模式,为后续的软件工程课程打下基础
- 架构师:建议将本书作为设计决策的参考框架,在系统设计中灵活运用23种模式解决实际问题
读完本书,你将掌握面向对象软件设计的23种经典模式,获得一套通用的设计语言和思考框架。需要注意的是,本书以C++为例讲解,但设计模式的思想和方法适用于所有面向对象编程语言(如Java、C#、Python等)。建议读者在学习本书的基础上,结合实际项目经验反复研读——正如许多读者所说:"第一遍看不懂是正常的,带着不成功的开发经历再读,会有完全不同的感悟。"