设计模式:可复用面向对象软件的基础

[美] Erich Gamma / Richard Helm / Ralph Johnson / John Vlissides
3 阅读 0 点赞 2026-04-29 IT 老游的虾
IT技术编程设计模式

软件工程领域最具影响力的经典著作,由GoF四人组撰写。全书系统介绍了23种经典设计模式,将面向对象设计的最佳实践归纳为可复用的解决方案。本书被誉为软件设计的圣经,影响了全球数代程序员的编程思维和架构设计能力。

本书速读

📖 本书核心内容

《设计模式》是软件工程领域最具影响力和里程碑意义的经典著作,于1994年首次出版。

由四位作者组成的GoF团队——Erich Gamma、Richard Helm、Ralph Johnson和John Vlissides——系统总结了面向对象设计的最佳实践。

全书介绍了23种经典设计模式,将这些模式分为创建型、结构型和行为型三大类。

本书被誉为软件设计的圣经,影响了全球数代程序员的编程思维和架构设计能力。

GoF的核心理念是:设计模式是对反复出现的问题的经过验证的解决方案。学习设计模式不是为了生搬硬套,而是为了在面对设计问题时能够快速地识别问题类型并选择合适的解决方案。

书中每种模式都包含模式名称、问题描述、解决方案、效果分析和代码示例,形成了一套完整的设计模式描述语言。

本书的出版标志着软件设计从经验主义走向系统化,为面向对象设计提供了一个共同的词汇表和参考框架。

虽然本书的示例代码基于C++和Smalltalk,但其中蕴含的设计思想适用于任何面向对象编程语言,包括Java、Python、JavaScript等现代语言。

本书的价值不仅在于介绍了23种具体的设计模式,更在于它提供了一套思考软件设计问题的方法论。通过学习和应用设计模式,开发者能够写出更加灵活、可维护和可扩展的代码。

设计模式的学习是一个循序渐进的过程,初学者应该先掌握几种最常用的模式,然后在实际项目中逐步应用和深化理解。随着经验的积累,开发者会逐渐形成对设计模式的直觉,能够在合适的时候选择合适的模式。设计模式不是银弹,它们不能解决所有的设计问题。但是,当开发者熟悉这些模式后,他们能够更快地识别常见的设计问题,并找到经过验证的解决方案。设计模式的价值在于它们提供了一个共同的词汇表,使团队成员能够更高效地沟通设计思想。一个团队如果都熟悉设计模式,他们在讨论架构和设计时就能够使用简洁而精确的语言,大大提高沟通效率。

🎯 设计模式的基础:接口编程与对象组合

设计模式的两大基石是接口编程和对象组合。

GoF强调,代码应该依赖于抽象接口而非具体实现。这样能够降低模块之间的耦合度,提高代码的灵活性和可测试性。当你需要替换一个组件的实现时,只要新实现遵循相同的接口,就不需要修改使用该组件的代码。这一原则是许多设计模式的基础,也是面向对象设计的核心原则之一。依赖倒置原则要求高层模块不应该依赖于低层模块,两者都应该依赖于抽象。抽象不应该依赖于具体实现,具体实现应该依赖于抽象。这一原则使系统能够更加灵活地应对变化,因为变化通常发生在具体实现层面,而抽象层相对稳定。通过依赖倒置,系统能够在不修改高层模块的情况下替换低层模块的实现,从而大大提高了系统的可维护性和可扩展性。

GoF指出,继承虽然能够实现代码复用,但会导致紧密的耦合和脆弱的基类问题。对象组合通过将功能委托给其他对象来实现复用,具有更高的灵活性和更低的耦合度。许多设计模式——如策略模式、装饰器模式、桥接模式——都是基于对象组合而非继承来实现的。组合优于继承是GoF提出的重要设计原则,它鼓励开发者优先考虑组合而非继承来实现代码复用。组合使系统能够在运行时动态地改变行为,而继承只能在编译时确定行为。这种运行时灵活性是面向对象设计的重要优势。通过组合,开发者可以根据需要在运行时选择不同的行为实现,而不需要修改现有的代码结构。组合还提供了更好的封装性,因为被组合的对象的内部实现细节对外部是隐藏的。

GoF建议识别系统中可能变化的部分,并将其封装起来。这样当变化发生时,只需要修改封装的部分,而不需要修改整个系统。封装变化点是设计模式的核心思想之一——工厂模式封装了对象创建的变化,策略模式封装了算法的变化,观察者模式封装了状态变化的通知机制。通过封装变化,系统能够更容易地适应新的需求和变化。识别变化点是架构设计的关键技能,它需要开发者对业务需求和技术趋势有深刻的理解。一个优秀的架构师能够预测未来可能的变化,并提前在架构中为这些变化预留空间。

🎯 创建型模式:灵活的对象创建

创建型模式关注的是如何灵活地创建对象。

抽象工厂模式提供了一个创建一系列相关或依赖对象的接口,而无需指定它们的具体类。比如一个UI框架可能需要创建按钮、文本框、菜单等组件,抽象工厂模式允许你根据不同的操作系统或主题创建不同风格的组件族。抽象工厂模式的核心优势是能够确保创建的组件之间是兼容的,同时隐藏了具体实现类的细节。当需要更换组件族时,只需要更换工厂实现即可,不需要修改使用这些组件的代码。抽象工厂模式在跨平台应用开发中非常有用,它能够为不同的平台创建一致的用户界面。

单例模式确保一个类只有一个实例,并提供一个全局访问点。比如配置文件管理器、数据库连接池、日志记录器等场景中,通常只需要一个实例。单例模式的实现需要注意线程安全和延迟初始化的问题。在多线程环境中,需要使用双重检查锁定或静态内部类来确保单例的正确性。单例模式虽然常用,但也应该谨慎使用,因为过度使用单例会导致代码难以测试和维护。单例模式的全局状态可能会隐藏模块之间的依赖关系,使代码的结构变得不清晰。

工厂方法模式定义了一个创建对象的接口,但由子类决定实例化哪个类。工厂方法模式将对象的创建延迟到子类,使父类可以不依赖于具体的产品类。这一模式在框架设计中非常常见——框架定义创建对象的接口,而由具体的应用程序决定创建哪种对象。工厂方法模式的核心优势是实现了创建逻辑和使用逻辑的分离,使系统更加灵活和可扩展。当需要添加新的产品类型时,只需要添加新的工厂子类,而不需要修改现有的代码。

建造者模式将一个复杂对象的构建过程分解为多个步骤,使同样的构建过程可以创建不同的表示。建造者模式适用于对象创建过程复杂、参数众多的场景。通过建造者模式,你可以将对象的构建逻辑与表示逻辑分离,使代码更加清晰和可维护。建造者模式在构建复杂配置对象、SQL查询构建器等场景中非常有用。建造者模式的核心优势是它能够提供一种流式的API,使对象的创建过程更加直观和易于理解。

🎯 结构型模式:灵活的对象组合

结构型模式关注的是如何组合类和对象以获得更大的结构。

适配器模式将一个类的接口转换为客户端期望的另一个接口。当你需要使用一个已有的类,但其接口与你的系统不兼容时,适配器模式能够提供解决方案。适配器模式的核心是创建一个适配器类,该类实现了目标接口,并将调用委托给被适配的类。适配器模式是系统集成和遗留代码改造中最常用的模式之一,它能够在不修改原有代码的情况下实现接口的兼容。适配器模式在第三方库集成、API版本升级等场景中非常有用。

装饰器模式允许在运行时动态地给对象添加新的行为,而不需要修改对象的类。装饰器模式通过创建一个包装类来实现——包装类实现了与被包装类相同的接口,并在调用被包装类的方法前后添加额外的行为。装饰器模式的核心优势是能够灵活地组合多个装饰器,实现复杂的行为组合。装饰器模式在I/O流处理、HTTP中间件等场景中广泛应用,它提供了一种优雅的扩展对象功能的方式。装饰器模式遵循开闭原则——对扩展开放,对修改关闭。

代理模式为另一个对象提供一个替身或占位符,以控制对这个对象的访问。代理模式的应用场景包括远程代理、虚拟代理、保护代理等。代理模式的核心是在客户端和真实对象之间添加一个中间层,以提供额外的控制和管理。远程代理可以隐藏网络通信的复杂性,虚拟代理可以实现延迟加载,保护代理可以控制访问权限。代理模式在分布式系统、缓存系统、权限管理系统中都有广泛的应用。

外观模式为子系统中的一组接口提供一个统一的界面。外观模式定义了一个高层接口,使子系统更加易于使用。当你面对一个复杂的子系统时,外观模式能够帮助你隐藏系统的复杂性,提供一个简单易用的接口。外观模式的核心优势是降低了客户端与子系统之间的耦合度,使客户端不需要了解子系统的内部结构和实现细节。外观模式在框架设计中非常常见,它为开发者提供了一个简化的API,隐藏了底层的复杂性。

🎯 行为型模式:灵活的对象交互

行为型模式关注的是对象之间的通信和职责分配。

观察者模式定义了一种一对多的依赖关系,当一个对象的状态发生变化时,所有依赖它的对象都会自动收到通知并更新。观察者模式是实现事件驱动架构的基础——比如GUI框架中的事件监听、消息队列中的发布订阅模型。观察者模式的核心优势是实现了观察者和被观察者之间的松耦合,使它们可以独立地变化和扩展。观察者模式在现代前端框架和响应式编程中得到了广泛应用,它是实现数据绑定和状态管理的核心机制。观察者模式使系统能够更加灵活地响应状态变化,而不需要在代码中硬编码依赖关系。

策略模式定义了一系列可互换的算法,并将每个算法封装在一个独立的类中。策略模式允许在运行时动态地选择和切换算法,而不需要修改使用算法的代码。策略模式的核心优势是将算法的实现与使用算法的代码分离,使算法可以独立地变化和扩展。策略模式在排序算法、支付策略、路由策略等场景中非常有用,它提供了一种灵活的方式来处理不同的业务规则。策略模式使系统能够在不修改核心逻辑的情况下添加新的算法实现。

迭代器模式提供了一种顺序访问聚合对象中各个元素的方法,而不需要暴露聚合对象的内部结构。迭代器模式是现代编程语言中foreach循环的基础——通过迭代器接口,客户端可以统一地遍历不同类型的集合,而不需要关心集合的具体实现。迭代器模式的核心优势是实现了遍历逻辑与集合实现的分离,使客户端代码更加简洁和通用。迭代器模式使集合的实现可以独立地变化,而不影响到使用这些集合的代码。

责任链模式将请求的发送者和接收者解耦,使多个对象都有机会处理这个请求。责任链模式将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。责任链模式适用于请求处理逻辑复杂、需要多个处理者的场景。责任链模式在日志记录、权限验证、请求过滤等场景中广泛应用,它提供了一种灵活的方式来处理不同类型的请求。责任链模式使系统能够动态地添加或移除处理者,而不需要修改现有的代码结构。

⭐ 金句摘录

设计模式是对反复出现的问题的经过验证的解决方案。

针对接口编程而非实现——这样能够降低模块之间的耦合度,提高代码的灵活性。

优先使用对象组合而非继承——组合具有更高的灵活性和更低的耦合度。

识别系统中可能变化的部分,并将其封装起来——这是设计模式的核心思想。

📚 阅读建议

适合有一定面向对象编程经验的程序员阅读。

建议不要试图一次性学习所有模式,而是先掌握几种最常用的模式,然后在实际项目中逐步应用。

重点阅读观察者模式、策略模式和工厂模式,这三种模式在日常开发中最常用。