【设计模式】设计模式学习总结

设计模式的核心设计原则

设计模式背后是面向对象的设计原则,它们是编写灵活可复用可维护软件的基础:

著名的SOLID原则 是指单一职责原则(SRP)开闭原则(OCP)里氏替换规则(LSP)接口隔离原则(ISP)依赖倒置原则(DIP)

设计模式

在软件开发中,设计模式是针对特定场景的常见问题可复用解决方案。它们由经验丰富的开发者总结而成,有助于提升代码的可维护性、复用性和扩展性。

模式大类 核心焦点 典型代表模式 理解
创建型模式(5种) 封装对象的创建过程,使系统与具体对象的类型和创建方式解耦 工厂方法、抽象工厂、建造者、原型、单例 它们像智能的"对象工厂",避免在代码中硬编码具体的类名。当需要新增产品类型时,创建型模式能供极大的灵活性,而无需修改大量现有代码
结构型模式(7种) 关注如何将类或对象组合成更大、更复杂的结果,以提升系统灵活性 适配器、桥接、组合、装饰器、外观、享元、代理 这类模式如同"组装说明书",它通过类继承和对象组合的方式,将多个小结构搭建为功能更强大、更灵活的大结构。例如适配器模式让不兼容的接口可以协同工作;装饰器模式可以动态地给对象添加新功能而不改变其结构
行为型模式(11种) 关注对象之间的职责分配和通信交流,优化对象间的交互流程 观察者、策略、模板方法、责任链、命令、状态 他们负责管理对象间的"协作关系",将程序中复杂的控制流清晰化。行为型模式通常将某个行为或算法封装成一个独立的对象,使得行为的变化不会影响到使用它的对象。例如,观察者模式实现了对象间一对多的依赖,当一个对象状态改变时,所有依赖它的对象都会自动得到通知

具体设计模式详情如下:

模式分类 模式名称 原理 使用场景 相似模式对比
创建型 工厂方法模式(Factory Method) 定义了一个创建对象的接口,但由子类决定实例化哪个类。工厂方法将对象的创建延迟到子类。 类无法预知预知它需要创建的具体类 VS 抽象工厂: 工厂方法创建一种产品,抽象工厂创建一族相关或依赖的产品
创建型 抽象工厂模式​ (Abstract Factory) 提供一个创建一系列相关或依赖的接口,而无需指定它们的具体类 系统需要独立于其产品创建、组合和表示时;系统又多个产品族之一被配置时 VS 建造者模式:两者都创建复杂对象。抽象共产关注产品族,建造者关注通过分步创建单个复杂对象
创建型 建造者模式(Builder) 将一个复杂对象的创建过程和其表示分离,使得同样的创建过程可以创建不同的表示 一个复杂对象的创建通常由多个部分组成,这些部分的组合经常变化,但组合的算法相对稳定。
创建型 原型模式(Prototype) 使用原型示例指定创建对象的种类,并通过拷贝这个原型来创建新的对象 当直接创建一个对象的成本较高时,采用拷贝现有实例的方式更高效 VS 单例模式:原型每次拷贝都产生新的实例;单例保证全局只有一个实例
创建型 单例模式(Singleton) 确保一个类只有一个实例,并提供全局访问点访问该实例 当需要控制实例数目,节省系统资源,如线程池、缓存、日志对象等。java 6 种单例实现方案
结构型 适配器模式(Adapter) 充当两个不兼容接口之间的桥梁,将一个类的接口转换成另一个类的接口,使得原本不兼容的类可以协同工作。旨在解决不同接口之间的兼容问题 需要使用现有的类,但是其接口不符合系统的要求 VS 装饰器模式 : 装饰器目的是动态添加功能,适配器模式是接口适配。 VS 代理模式: 适配器是为了解决接口不兼容问题,会改变接口,代理模式是提供对象的替代或访问控制,不改变接口
结构型 桥接模式(Bridge) 用于将抽象部分和实现部分 分离,使得他们可以独立变化 一个类存在多个独立变化的维度,且这些维度都需要扩展,避免使用继承导致的类爆炸。桥接模式提供了灵活的扩展方式 VS 适配器模式:桥接模式是事前设计,为使抽象和实现都可以独立变化,适配器是事后补救,为使不兼容的接口协同工作
结构型 组合模式(Composite) 将对象组合成树形结构以表示"部分-整体"的层次结构。组合模式使得用户对单个对象和组合对象使用具有一致性 简化树形结构的处理,以统一的方式处理树形结构中的所有对象
结构型 装饰器模式(Decorator) 动态地给对象添加功能,同时不改变其结构。装饰器通过将对象包装在装饰类中,可在保持类方法签名不变的情况,动态修改其行为,提供了一种灵活的替代继承方式扩展功能的方法 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责;替代通过继承方式扩展能力的方式 VS 代理模式:装饰器模式目的在于增强功能,代理模式目的在于控制访问
结构型 外观模式(Facade) 为一个复杂的子系统提供一个统一的高层接口,使子系统易于使用 为复杂的子系统提供简单易用的接口,降低客户端与子系统的耦合度 VS 中介者模式 : 外观模式处理的是不同类之间的依赖,中介者模式处理的是复杂对象之间的交互关系 VS 适配器模式:适配器模式是解决接口适配问题, 外观模式为复杂子系统提供简单易用的接口,简化复杂子系统的使用
结构型 享元模式(Flyweight) 通过共享对象的技术来减少创建大量相似对象的内存消耗,从而有效支持大量细粒度的对象复用 系统使用大量相同或相似的对象;对象的创建或销毁成本高;对象的大部分状态可以外部化,即对象的部分状态可以独立于对象本身存在(实现时需区分内部状态和外部状态)
结构型 代理模式(Proxy) 为其他对象提供一种代理,以控制对该对象的访问 直接访问某些对象时遇到问题:创建成本高、需要安全控制或远程访问等
行为型 职责链模式(Chain of Responsibility) 将处理者组成一条链,请求沿着该链传递 解耦请求发送者和处理者,使多个对象都有可能处理该请求,而发送者不需要知道具体哪个处理者处理 VS 命令模式: 责任链模式请求者不知道处理者是谁,命令模式请求者需要知道接收者并将其与命令绑定
行为型 命令模式(Command) 将请求封装成一个对象,从而可以使用不同的请求对客户进行参数化,支持请求排队、记录日志、撤销等操作 需要将请求发出者和处理者之间解耦;需要支持命令的撤销、重做等
行为型 解释器模式(Interpreter) 定义一种语言的文法表示,并创建一个解释器,该解释器能够解释该语言的句子 当有一种语言需要解释时,且可将该语言的句子表示为抽象语法树
行为型 迭代器模式(Iterator) 允许顺序访问聚合对象中的元素,同时不保留其内部表示 需要遍历一个聚合对象中的元素,又不想暴露其内部表示;提供一种统一的方法遍历不同的聚合对象 VS 访问者模式:迭代器模式主要关注的是聚合对象的遍历,访问者模式主要关注的是作用于数据结构对象上的操作
行为型 中介者模式(Mediator) 定义一个中介者对象来封装一系列对象间的交互,使各对象间解耦,且可独立改变他们之间的交互 当系统中多个类相互耦合,形成网状接口;对象间存在一对多关联
行为型 备忘录模式(Memento) 在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这些状态,以便在将来恢复到该状态,实现撤销和回滚操作 需要提供一种撤销机制,以便用户回退到之前的状态
行为型 观察者模式(Observer) 定义对象间的一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新 一个对象的状态变化时需要通知其他对象
行为型 状态模式(State) 允许一个对象在其内部状态改变时改变他的行为,看起来就像改变其类一样 对象的行为取决于它的状态,并且它必须在运行时根据状态改变它的行为;一个操作中包含大量的分支语句,这些分支依赖对象的状态 VS 策略模式: 状态模式中状态是由状态对象自身在内部触发,不同状态行为不同;策略模式中,策略由客户端选择,策略之间是平行、可互换的算法
行为型 策略模式(Strategy) 定义一系列的算法,把他们一个个封装起来,并且使用它们可相互替换。通过使用策略模式,可以在运行时根据需要选择不同的算法,而不需要修改客户端代码 许多相关的类仅仅是行为有差异,需要根据不同场景切换到不同算法或策略 VS 模板方法模式: 策略模式使整个算法可替换;模板方法模式固定算法骨架,只允许子类重定义算法的某些特定步骤
行为型 模板方法模式(Template Method) 在父类中定义了算法骨架,并允许子类在不改变算法结构的情况下重新定义算法的某些步骤 存在一个通用算法,但其中某些步骤在不同子类有不同实现
行为型 访问者模式(Visitor) 将数据结构与在该数据结构上执行的操作分离,使得操作可以独立数据结构变化 当对一个数据结构对象执行多个不同且不想关的操作,通过访问者模式解耦稳定的数据结构与易变的操作

扩展:代码质量的7个标准

  • 可维护性:可维护性强的代码意味着在不破坏原有设计或引入新bug的前提下,能够快速修改或新增代码
  • 可读性:高可读性的代码通过清晰的命名和结构,使得代码的意图易于理解,减少后期维护的难度。代码可读性直接影响代码的可维护性。
  • 可扩展性:代码通过扩展的方式添加新功能,而不需要修改原有代码。背后的原则:开闭原则。
  • 灵活性:代码能够在添加新功能时,已有代码不受影响且能够灵活的接纳新代码。灵活的代码设计通常通过依赖注入和接口实现,使系统能够根据不同场景动态切换实现
  • 简洁性:要求代码遵从KISS(Keep It Simple, Stupid)原则,避免过度复杂化。代码应当尽量简单,便于他人理解和维护
  • 可复用性:代码能够在不同场景下重复使用,避免重复编写相同的代码。高可复用性往往通过抽象和模块化设计实现
  • 可测试行:要求代码能够方便地进行单元测试。难以测试的代码往往耦合了多种逻辑,使得测试变得复杂且不直观。易于测试的代码通常通过依赖注入、接口和模块化设计实现。

可扩展性 vs 灵活性

  • 可扩展性:侧重于未来功能的扩展,确保系统在增加新功能时不需要大规模修改现有代码。主要关注的是系统如何在不改变原有代码的情况下新增功能
  • 灵活性:侧重于在不同条件下灵活应对变化,确保系统能够根据需求动态选择不同的实现方式。主要关注的是系统在运行时能够灵活的切换不同的实现或配置
相关推荐
小裕哥略帅3 小时前
PMP知识--五大过程组
笔记·学习
小屁猪qAq3 小时前
设计模式的基石
开发语言·c++·设计模式
Aliex_git3 小时前
提示词工程学习笔记
人工智能·笔记·学习
FAFU_kyp3 小时前
Rust 流程控制学习教程
学习·算法·rust
刘孬孬沉迷学习3 小时前
【5G&6G NTN】卫星通信学习系列1
学习·5g·卫星通信·ntn·移动通信·卫星·星地通信
航Hang*3 小时前
Photoshop 图形与图像处理技术——第9章:实践训练6——滤镜特效
图像处理·笔记·学习·ui·photoshop
一条闲鱼_mytube3 小时前
智能体设计模式(一):提示链、路由与并行化
人工智能·设计模式
renhongxia13 小时前
大型语言模型性能预测器:学习何时在混合人机-人工智能管理系统中升级
人工智能·深度学习·学习·机器学习·语言模型·自然语言处理
知识分享小能手3 小时前
Oracle 19c入门学习教程,从入门到精通,SQL*Plus命令详解:语法、使用方法与综合案例 -知识点详解(4)
sql·学习·oracle