软考中设计模式相关知识点总结

8 阅读13分钟

一、设计模式的基本概念

设计模式是在特定环境下,为了解决某一类问题而提出的经过验证的解决方案。每个设计模式都描述了一个在不断重复发生的问题,以及该问题的核心解决方案。通过这种方式,设计模式帮助开发者将日常遇到的问题及其解决方案系统化、模板化,使得代码更加易于理解、复用和维护。

二、设计模式的分类

根据设计模式的用途和目标,可以将其分为创建型、结构型和行为型三类。

  1. 创建型模式:关注对象的创建过程,通过控制对象的创建来降低系统的耦合度。常见的创建型模式有单例模式、工厂模式、抽象工厂模式、建造者模式和原型模式等。

  2. 结构型模式:关注类和对象的组合,通过类和对象的组合来形成更大的结构以解决更复杂的问题。常见的结构型模式有适配器模式、桥接模式、组合模式、装饰器模式、外观模式、享元模式和代理模式等。

  3. 行为型模式:关注对象之间的通信和协作,通过对象之间的通信和协作来实现更复杂的业务逻辑。常见的行为型模式有观察者模式、模板方法模式、策略模式、状态模式、责任链模式、解释器模式、迭代器模式、备忘录模式、中介者模式和访问者模式等。

三、重要设计模式详解

(一)创建型模式

  1. 单例模式

    • 定义:确保一个类只有一个实例,并提供一个全局访问点来获取该实例。
    • 实现要点:私有构造函数,防止外部实例化;静态成员变量保存唯一实例;提供静态方法获取实例。
    • 线程安全实现方式
      • 双重检查锁(DCL) :适用于 Java/C# 等语言,在获取实例时进行两次检查,提高性能且保证线程安全。
      • 静态内部类 :利用类加载机制实现延迟加载且线程安全。
    • 应用场景:常用于需要频繁创建和销毁的对象,或者创建对象需要消耗大量资源的场景,如数据库连接池、线程池的管理。
  2. 工厂模式

    • 工厂方法模式

      • 定义:定义一个用于创建对象的接口,但由子类决定实例化哪个类。
      • 类图结构
        • 抽象工厂类(Creator) :声明工厂方法(如 createProduct ())。
        • 具体工厂类(ConcreteCreator) :实现工厂方法,返回具体产品对象。
        • 抽象产品类(Product) :定义产品的接口。
        • 具体产品类(ConcreteProduct) :实现产品接口。
      • 应用场景:日志记录器(不同格式的日志,如文件、数据库);数据库连接(不同数据库驱动,如 MySQL、Oracle)。
      • 优点:符合开闭原则,新增产品只需扩展子类;客户端代码与具体产品解耦。
    • 抽象工厂模式

      • 定义:提供一个接口,用于创建相关或依赖对象的家族,而无需指定具体类。
      • 类图结构
        • 抽象工厂接口(AbstractFactory) :声明一组创建产品的方法(如 createButton (), createTextBox () )。
        • 具体工厂类(ConcreteFactory) :实现接口,生成同一产品族的具体对象。
        • 抽象产品接口(Button, TextBox) :定义产品的功能。
        • 具体产品类(WindowsButton, MacButton) :实现不同平台的组件。
      • 与工厂方法的区别:工厂方法针对单一产品等级结构;抽象工厂针对多个产品等级结构(产品族)。
      • 缺点:扩展新产品族困难(需修改抽象工厂接口)。
  3. 建造者模式

    • 定义:将一个复杂对象的构造过程与表示分离,使得同样的构建过程可以创建不同的表示。
    • 类图结构
      • 抽象建造者(Builder) :定义构建步骤的抽象接口(如 buildPartA (), buildPartB ()
      • 具体建造者(ConcreteBuilder) :实现构建步骤,提供获取结果的接口。
      • 指挥者(Director) :构造一个使用 Builder 接口的对象。
      • 产品(Product) :最终构建的复杂对象。
    • 应用场景:生成复杂对象(如 XML 文档、HTML 报表);创建具有多个可选参数的对象(避免构造函数参数爆炸)。
  4. 原型模式

    • 定义:用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象。
    • 实现要点:实现 Cloneable 接口(Java)或深拷贝逻辑;提供 clone () 方法(浅拷贝需谨慎处理引用类型)。
    • 应用场景:对象创建成本较高(如数据库查询结果缓存后复制);需要动态配置对象属性(如游戏中的敌人克隆)。
    • 深拷贝与浅拷贝
      • 浅拷贝 :复制基本类型字段,引用类型字段共享同一对象。
      • 深拷贝 :引用类型字段也递归复制。

(二)结构型模式

  1. 适配器模式

    • 定义:将一个类的接口转换成客户希望的另一个接口。
    • 实现方式
      • 类适配器 :通过继承适配者类实现目标接口。
      • 对象适配器 :通过组合适配者对象实现目标接口。
    • 应用场景:整合第三方库(如不同格式的日志接口转换);旧系统接口升级兼容。
  2. 装饰器模式

    • 定义:动态地为对象添加额外职责,避免子类膨胀。
    • 结构
      • 组件接口(Component) :定义一个对象接口,可以对这些对象动态地添加职责。
      • 具体组件(ConcreteComponent) :定义一个对象,可以对这个对象添加一些职责。
      • 装饰器基类(Decorator) :继承组件接口,持有组件实例。
      • 具体装饰器(ConcreteDecorator) :添加附加功能。
    • 应用场景:Java I/O 流(如 BufferedInputStream 装饰 FileInputStream);动态扩展对象行为(如为订单添加折扣、税费计算)。
  3. 代理模式

    • 定义:为其他对象提供一种代理以控制对这个对象的访问。
    • 类型
      • 虚拟代理 :延迟加载(如图片懒加载)。
      • 保护代理 :控制访问权限。
      • 远程代理 :跨网络访问对象(如 RPC)。
    • 应用场景:Spring AOP 中的动态代理(JDK 动态代理、CGLIB);访问敏感资源时的权限校验。
  4. 组合模式

    • 定义:将对象组合成树形结构以表示 “部分 - 整体” 层次,使客户端统一处理单个对象和组合对象。
    • 结构
      • 组件接口(Component) :定义叶子节点和容器的公共操作(如 add (), remove () )。
      • 叶子节点(Leaf) :无子节点,实现基础操作。
      • 复合节点(Composite) :包含子组件,管理子组件集合。
    • 应用场景:文件系统(文件与文件夹的统一操作);GUI 容器控件(如 Panel 包含 Button、Label 等)。
  5. 外观模式

    • 定义:为子系统中的一组接口提供一个一致的界面,简化客户端调用。
    • 应用场景:复杂 API 的简化封装(如支付系统的统一入口);微服务网关聚合多个服务接口。
  6. 桥接模式

    • 定义:将抽象部分与实现部分分离,使两者可以独立变化。

    • 优势:避免多层继承导致的类爆炸,支持多维度扩展(如形状与颜色的组合)。

  7. 享元模式

    • 定义:运用共享技术有效地支持大量细粒度的对象。
    • 关键点
      • 内部状态 :可共享的部分(如字符的 Unicode 值)。
      • 外部状态 :不可共享,随环境变化(如字符的颜色、大小)。

(三)行为型模式

  1. 观察者模式

    • 定义:定义对象之间的一对多依赖关系,当一个对象状态改变时,其相关依赖对象都会收到通知并自动更新。
    • 结构
      • 主题(Subject) :被观察的对象,维护观察者列表,提供添加、删除观察者以及通知观察者的方法。
      • 观察者(Observer) :定义更新接口,当主题状态改变时接收通知并执行相应操作。
    • 应用场景:常用于实现事件监听和消息通知等功能,如 GUI 系统中的按钮点击事件、股票交易系统中的价格变动事件。
  2. 策略模式

    • 定义:定义一系列的算法,并将每一个算法封装起来,使它们可以互相替换。
    • 结构
      • 抽象策略(Strategy) :定义算法的抽象接口。
      • 具体策略(ConcreteStrategy) :实现抽象策略接口,具体的算法实现。
      • 环境(Context) :持有一个抽象策略对象的引用,根据不同情况选择不同的具体策略对象来执行算法。
    • 应用场景:算法可以独立于使用它的客户端变化的场景,如电商系统中的不同促销策略。
  3. 模板方法模式

    • 定义:定义一个操作中的算法骨架,而将一些步骤延迟到子类中实现。
    • 结构
      • 抽象类(AbstractClass) :定义模板方法,包含算法骨架,以及一些抽象方法和具体方法。抽象方法由子类实现,具体方法在抽象类中已经实现。
      • 具体子类(ConcreteClass) :实现抽象类中的抽象方法,完成特定步骤的实现。
    • 应用场景:多个子类有相同的算法结构,但某些步骤的实现不同,如不同类型文档的生成流程。
  4. 责任链模式

    • 定义:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。
    • 结构
      • 抽象处理者(Handler) :定义处理请求的抽象接口,包含后继处理者的引用以及处理请求的方法
      • 具体处理者(ConcreteHandler) :实现抽象处理者接口,在自己能够处理请求时处理请求,否则将请求转发给后继处理者。
    • 应用场景:审批流程(如请假审批、费用报销审批);错误处理链。
  5. 状态模式

    • 定义:允许一个对象在其内部状态改变时改变它的行为。
    • 结构
      • 环境(Context) :持有一个状态对象的引用,定义客户感兴趣的接口,并根据当前状态调用状态对象的相应方法。
      • 抽象状态(State) :定义一个接口以封装与环境的一个特定状态相关的行为。
      • 具体状态(ConcreteState) :实现抽象状态接口,每个具体状态类实现了与环境的一个状态相关的行为。
    • 应用场景:对象行为随状态改变而改变的场景,如游戏角色的不同状态(正常、中毒、无敌)下有不同行为。
  6. 迭代器模式

    • 定义:提供一种方法顺序访问一个聚合对象中的各个元素,且不需要暴露该对象的内部表示。
    • 结构
      • 迭代器(Iterator) :定义遍历元素的接口,包括获取下一个元素、判断是否还有下一个元素等方法。
      • 具体迭代器(ConcreteIterator) :实现迭代器接口,对具体的聚合对象进行遍历。
      • 聚合(Aggregate) :定义创建迭代器对象的接口。
      • 具体聚合(ConcreteAggregate) :实现聚合接口,返回一个具体迭代器对象,该对象可以遍历其内部元素。
    • 应用场景:对各种集合对象进行遍历操作,如 Java 中的集合框架。
  7. 备忘录模式

    • 定义:在不破坏封装性的前提下捕获一个对象的内部状态,并在对象之外保存这个状态。这样以后就可以将对象恢复到原先保存的状态。
    • 结构
      • 发起人(Originator) :创建备忘录,记录自身的内部状态;使用备忘录恢复自身状态。
      • 备忘录(Memento) :存储发起人的内部状态。
      • 管理者(Caretaker) :负责保存备忘录,但不能对备忘录的内容进行操作或检查。
    • 应用场景:实现撤销操作(如文本编辑器的撤销功能);游戏存档与读档。
  8. 中介者模式

    • 定义:用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
    • 结构
      • 中介者(Mediator) :定义一个接口用于各同事对象之间的通信。
      • 具体中介者(ConcreteMediator) :实现中介者接口,协调各同事对象之间的交互,了解并维护它的各个同事。
      • 同事(Colleague) :每个同事类都知道它的中介者对象,每个同事对象在需要与其他同事对象通信时,与它的中介者通信。
    • 应用场景:多个对象之间存在复杂的交互关系,如聊天室系统、MVC 架构中的控制器。
  9. 解释器模式

    • 定义:给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。
    • 结构
      • 抽象表达式(AbstractExpression) :声明一个抽象的解释操作,这个接口为抽象语法树中所有的节点所共享。
      • 终结符表达式(TerminalExpression) :实现与文法中的终结符相关联的解释操作。
      • 非终结符表达式(NonterminalExpression) :对文法中的非终结符进行解释。
      • 环境(Context) :包含解释器之外的一些全局信息。
    • 应用场景:编译器、正则表达式解析。
  10. 访问者模式

    • 定义:表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素类的前提下定义作用于这些元素的新操作。
    • 结构
      • 访问者(Visitor) :为该对象结构中具体元素角色声明一个访问操作接口。
      • 具体访问者(ConcreteVisitor) :实现访问者声明的接口,每个操作实现算法的一部分,而该算法片段乃是对应于结构中相应的具体元素角色。
      • 元素(Element) :定义一个接受访问操作的接口,该操作以一个访问者作为参数。
      • 具体元素(ConcreteElement) :实现接受操作,调用访问者的访问操作以处理该元素。
      • 对象结构(ObjectStructure) :能枚举它的元素,可以提供一个高层的接口以允许访问者访问它的元素。
    • 应用场景:对象结构相对稳定,但需要经常对其元素进行新的操作,如对不同类型的图形元素进行不同的操作(计算面积、绘制等)。

四、设计模式的实践应用

在实际软件开发过程中,设计模式的应用需要根据具体的业务场景和需求来选择。合理地使用设计模式可以提高代码的可读性、可维护性和可扩展性,降低系统的复杂度和开发成本。例如,在开发一个电商系统时,对于用户管理模块,可以使用单例模式来管理用户登录状态;在订单处理模块,使用策略模式来实现不同的支付策略;对于系统的整体架构,可以使用外观模式来提供简洁的接口给外部调用。

设计模式是软件工程中非常重要的概念,它们在软考中占有重要地位。掌握设计模式的基本概念和分类,理解常见设计模式的原理和应用场景,对于提高软件开发能力和通过软考具有重要意义。在实际应用中,开发者应根据具体需求灵活选择和使用设计模式,以实现高质量、高效率的软件开发。